diff options
author | emaste <emaste@FreeBSD.org> | 2013-08-23 18:06:42 +0000 |
---|---|---|
committer | emaste <emaste@FreeBSD.org> | 2013-08-23 18:06:42 +0000 |
commit | 424d4dadd208e2a1e9a43c3d55f47f03ba0c4509 (patch) | |
tree | 05d762b98a499804ce690e6ce04033f1ddf4dee6 /contrib/llvm/tools/lldb/source/Interpreter | |
parent | cde487f27a84e02a560384f75178fddca68740f6 (diff) | |
parent | dcd15f81789e389c1cb27d264fcdddfd0a6002bd (diff) | |
download | FreeBSD-src-424d4dadd208e2a1e9a43c3d55f47f03ba0c4509.zip FreeBSD-src-424d4dadd208e2a1e9a43c3d55f47f03ba0c4509.tar.gz |
Merge lldb r188801 to contrib/llvm/tools/lldb/
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Interpreter')
44 files changed, 16870 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/Args.cpp b/contrib/llvm/tools/lldb/source/Interpreter/Args.cpp new file mode 100644 index 0000000..e6d2043 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/Args.cpp @@ -0,0 +1,1789 @@ +//===-- Args.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/lldb-python.h" + +// C Includes +#include <getopt.h> +#include <cstdlib> +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/Args.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/StreamString.h" +#include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Interpreter/Options.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Process.h" +//#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +//#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Args constructor +//---------------------------------------------------------------------- +Args::Args (const char *command) : + m_args(), + m_argv(), + m_args_quote_char() +{ + if (command) + SetCommandString (command); +} + + +Args::Args (const char *command, size_t len) : + m_args(), + m_argv(), + m_args_quote_char() +{ + if (command && len) + SetCommandString (command, len); +} + +//---------------------------------------------------------------------- +// We have to be very careful on the copy constructor of this class +// to make sure we copy all of the string values, but we can't copy the +// rhs.m_argv into m_argv since it will point to the "const char *" c +// strings in rhs.m_args. We need to copy the string list and update our +// own m_argv appropriately. +//---------------------------------------------------------------------- +Args::Args (const Args &rhs) : + m_args (rhs.m_args), + m_argv (), + m_args_quote_char(rhs.m_args_quote_char) +{ + UpdateArgvFromArgs(); +} + +//---------------------------------------------------------------------- +// We have to be very careful on the copy constructor of this class +// to make sure we copy all of the string values, but we can't copy the +// rhs.m_argv into m_argv since it will point to the "const char *" c +// strings in rhs.m_args. We need to copy the string list and update our +// own m_argv appropriately. +//---------------------------------------------------------------------- +const Args & +Args::operator= (const Args &rhs) +{ + // Make sure we aren't assigning to self + if (this != &rhs) + { + m_args = rhs.m_args; + m_args_quote_char = rhs.m_args_quote_char; + UpdateArgvFromArgs(); + } + return *this; +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +Args::~Args () +{ +} + +void +Args::Dump (Stream *s) +{ + const size_t argc = m_argv.size(); + for (size_t i=0; i<argc; ++i) + { + s->Indent(); + const char *arg_cstr = m_argv[i]; + if (arg_cstr) + s->Printf("argv[%zi]=\"%s\"\n", i, arg_cstr); + else + s->Printf("argv[%zi]=NULL\n", i); + } + s->EOL(); +} + +bool +Args::GetCommandString (std::string &command) const +{ + command.clear(); + const size_t argc = GetArgumentCount(); + for (size_t i=0; i<argc; ++i) + { + if (i > 0) + command += ' '; + command += m_argv[i]; + } + return argc > 0; +} + +bool +Args::GetQuotedCommandString (std::string &command) const +{ + command.clear (); + const size_t argc = GetArgumentCount(); + for (size_t i = 0; i < argc; ++i) + { + if (i > 0) + command.append (1, ' '); + char quote_char = GetArgumentQuoteCharAtIndex(i); + if (quote_char) + { + command.append (1, quote_char); + command.append (m_argv[i]); + command.append (1, quote_char); + } + else + command.append (m_argv[i]); + } + return argc > 0; +} + +void +Args::SetCommandString (const char *command, size_t len) +{ + // Use std::string to make sure we get a NULL terminated string we can use + // as "command" could point to a string within a large string.... + std::string null_terminated_command(command, len); + SetCommandString(null_terminated_command.c_str()); +} + +void +Args::SetCommandString (const char *command) +{ + m_args.clear(); + m_argv.clear(); + m_args_quote_char.clear(); + + if (command && command[0]) + { + static const char *k_space_separators = " \t"; + static const char *k_space_separators_with_slash_and_quotes = " \t \\'\""; + const char *arg_end = NULL; + const char *arg_pos; + for (arg_pos = command; + arg_pos && arg_pos[0]; + arg_pos = arg_end) + { + // Skip any leading space separators + const char *arg_start = ::strspn (arg_pos, k_space_separators) + arg_pos; + + // If there were only space separators to the end of the line, then + // we're done. + if (*arg_start == '\0') + break; + + // Arguments can be split into multiple discontiguous pieces, + // for example: + // "Hello ""World" + // this would result in a single argument "Hello World" (without/ + // the quotes) since the quotes would be removed and there is + // not space between the strings. So we need to keep track of the + // current start of each argument piece in "arg_piece_start" + const char *arg_piece_start = arg_start; + arg_pos = arg_piece_start; + + std::string arg; + // Since we can have multiple quotes that form a single command + // in a command like: "Hello "world'!' (which will make a single + // argument "Hello world!") we remember the first quote character + // we encounter and use that for the quote character. + char first_quote_char = '\0'; + char quote_char = '\0'; + bool arg_complete = false; + + do + { + arg_end = ::strcspn (arg_pos, k_space_separators_with_slash_and_quotes) + arg_pos; + + switch (arg_end[0]) + { + default: + assert (!"Unhandled case statement, we must handle this..."); + break; + + case '\0': + // End of C string + if (arg_piece_start && arg_piece_start[0]) + arg.append (arg_piece_start); + arg_complete = true; + break; + + case '\\': + // Backslash character + switch (arg_end[1]) + { + case '\0': + arg.append (arg_piece_start); + ++arg_end; + arg_complete = true; + break; + + default: + if (quote_char == '\0') + { + arg.append (arg_piece_start, arg_end - arg_piece_start); + if (arg_end[1] != '\0') + { + arg.append (arg_end + 1, 1); + arg_pos = arg_end + 2; + arg_piece_start = arg_pos; + } + } + else + arg_pos = arg_end + 2; + break; + } + break; + + case '"': + case '\'': + case '`': + // Quote characters + if (quote_char) + { + // We found a quote character while inside a quoted + // character argument. If it matches our current quote + // character, this ends the effect of the quotes. If it + // doesn't we ignore it. + if (quote_char == arg_end[0]) + { + arg.append (arg_piece_start, arg_end - arg_piece_start); + // Clear the quote character and let parsing + // continue (we need to watch for things like: + // "Hello ""World" + // "Hello "World + // "Hello "'World' + // All of which will result in a single argument "Hello World" + quote_char = '\0'; // Note that we are no longer inside quotes + arg_pos = arg_end + 1; // Skip the quote character + arg_piece_start = arg_pos; // Note we are starting from later in the string + } + else + { + // different quote, skip it and keep going + arg_pos = arg_end + 1; + } + } + else + { + // We found the start of a quote scope. + // Make sure there isn't a string that precedes + // the start of a quote scope like: + // Hello" World" + // If so, then add the "Hello" to the arg + if (arg_end > arg_piece_start) + arg.append (arg_piece_start, arg_end - arg_piece_start); + + // Enter into a quote scope + quote_char = arg_end[0]; + + if (first_quote_char == '\0') + first_quote_char = quote_char; + + arg_pos = arg_end; + ++arg_pos; // Skip the quote character + arg_piece_start = arg_pos; // Note we are starting from later in the string + + // Skip till the next quote character + const char *end_quote = ::strchr (arg_piece_start, quote_char); + while (end_quote && end_quote[-1] == '\\') + { + // Don't skip the quote character if it is + // preceded by a '\' character + end_quote = ::strchr (end_quote + 1, quote_char); + } + + if (end_quote) + { + if (end_quote > arg_piece_start) + arg.append (arg_piece_start, end_quote - arg_piece_start); + + // If the next character is a space or the end of + // string, this argument is complete... + if (end_quote[1] == ' ' || end_quote[1] == '\t' || end_quote[1] == '\0') + { + arg_complete = true; + arg_end = end_quote + 1; + } + else + { + arg_pos = end_quote + 1; + arg_piece_start = arg_pos; + } + quote_char = '\0'; + } + else + { + // Consume the rest of the string as there was no terminating quote + arg.append(arg_piece_start); + arg_end = arg_piece_start + strlen(arg_piece_start); + arg_complete = true; + } + } + break; + + case ' ': + case '\t': + if (quote_char) + { + // We are currently processing a quoted character and found + // a space character, skip any spaces and keep trying to find + // the end of the argument. + arg_pos = ::strspn (arg_end, k_space_separators) + arg_end; + } + else + { + // We are not inside any quotes, we just found a space after an + // argument + if (arg_end > arg_piece_start) + arg.append (arg_piece_start, arg_end - arg_piece_start); + arg_complete = true; + } + break; + } + } while (!arg_complete); + + m_args.push_back(arg); + m_args_quote_char.push_back (first_quote_char); + } + UpdateArgvFromArgs(); + } +} + +void +Args::UpdateArgsAfterOptionParsing() +{ + // Now m_argv might be out of date with m_args, so we need to fix that + arg_cstr_collection::const_iterator argv_pos, argv_end = m_argv.end(); + arg_sstr_collection::iterator args_pos; + arg_quote_char_collection::iterator quotes_pos; + + for (argv_pos = m_argv.begin(), args_pos = m_args.begin(), quotes_pos = m_args_quote_char.begin(); + argv_pos != argv_end && args_pos != m_args.end(); + ++argv_pos) + { + const char *argv_cstr = *argv_pos; + if (argv_cstr == NULL) + break; + + while (args_pos != m_args.end()) + { + const char *args_cstr = args_pos->c_str(); + if (args_cstr == argv_cstr) + { + // We found the argument that matches the C string in the + // vector, so we can now look for the next one + ++args_pos; + ++quotes_pos; + break; + } + else + { + quotes_pos = m_args_quote_char.erase (quotes_pos); + args_pos = m_args.erase (args_pos); + } + } + } + + if (args_pos != m_args.end()) + m_args.erase (args_pos, m_args.end()); + + if (quotes_pos != m_args_quote_char.end()) + m_args_quote_char.erase (quotes_pos, m_args_quote_char.end()); +} + +void +Args::UpdateArgvFromArgs() +{ + m_argv.clear(); + arg_sstr_collection::const_iterator pos, end = m_args.end(); + for (pos = m_args.begin(); pos != end; ++pos) + m_argv.push_back(pos->c_str()); + m_argv.push_back(NULL); + // Make sure we have enough arg quote chars in the array + if (m_args_quote_char.size() < m_args.size()) + m_args_quote_char.resize (m_argv.size()); +} + +size_t +Args::GetArgumentCount() const +{ + if (m_argv.empty()) + return 0; + return m_argv.size() - 1; +} + +const char * +Args::GetArgumentAtIndex (size_t idx) const +{ + if (idx < m_argv.size()) + return m_argv[idx]; + return NULL; +} + +char +Args::GetArgumentQuoteCharAtIndex (size_t idx) const +{ + if (idx < m_args_quote_char.size()) + return m_args_quote_char[idx]; + return '\0'; +} + +char ** +Args::GetArgumentVector() +{ + if (!m_argv.empty()) + return (char **)&m_argv[0]; + return NULL; +} + +const char ** +Args::GetConstArgumentVector() const +{ + if (!m_argv.empty()) + return (const char **)&m_argv[0]; + return NULL; +} + +void +Args::Shift () +{ + // Don't pop the last NULL terminator from the argv array + if (m_argv.size() > 1) + { + m_argv.erase(m_argv.begin()); + m_args.pop_front(); + if (!m_args_quote_char.empty()) + m_args_quote_char.erase(m_args_quote_char.begin()); + } +} + +const char * +Args::Unshift (const char *arg_cstr, char quote_char) +{ + m_args.push_front(arg_cstr); + m_argv.insert(m_argv.begin(), m_args.front().c_str()); + m_args_quote_char.insert(m_args_quote_char.begin(), quote_char); + return GetArgumentAtIndex (0); +} + +void +Args::AppendArguments (const Args &rhs) +{ + const size_t rhs_argc = rhs.GetArgumentCount(); + for (size_t i=0; i<rhs_argc; ++i) + AppendArgument(rhs.GetArgumentAtIndex(i)); +} + +void +Args::AppendArguments (const char **argv) +{ + if (argv) + { + for (uint32_t i=0; argv[i]; ++i) + AppendArgument(argv[i]); + } +} + +const char * +Args::AppendArgument (const char *arg_cstr, char quote_char) +{ + return InsertArgumentAtIndex (GetArgumentCount(), arg_cstr, quote_char); +} + +const char * +Args::InsertArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char) +{ + // Since we are using a std::list to hold onto the copied C string and + // we don't have direct access to the elements, we have to iterate to + // find the value. + arg_sstr_collection::iterator pos, end = m_args.end(); + size_t i = idx; + for (pos = m_args.begin(); i > 0 && pos != end; ++pos) + --i; + + pos = m_args.insert(pos, arg_cstr); + + if (idx >= m_args_quote_char.size()) + { + m_args_quote_char.resize(idx + 1); + m_args_quote_char[idx] = quote_char; + } + else + m_args_quote_char.insert(m_args_quote_char.begin() + idx, quote_char); + + UpdateArgvFromArgs(); + return GetArgumentAtIndex(idx); +} + +const char * +Args::ReplaceArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char) +{ + // Since we are using a std::list to hold onto the copied C string and + // we don't have direct access to the elements, we have to iterate to + // find the value. + arg_sstr_collection::iterator pos, end = m_args.end(); + size_t i = idx; + for (pos = m_args.begin(); i > 0 && pos != end; ++pos) + --i; + + if (pos != end) + { + pos->assign(arg_cstr); + assert(idx < m_argv.size() - 1); + m_argv[idx] = pos->c_str(); + if (idx >= m_args_quote_char.size()) + m_args_quote_char.resize(idx + 1); + m_args_quote_char[idx] = quote_char; + return GetArgumentAtIndex(idx); + } + return NULL; +} + +void +Args::DeleteArgumentAtIndex (size_t idx) +{ + // Since we are using a std::list to hold onto the copied C string and + // we don't have direct access to the elements, we have to iterate to + // find the value. + arg_sstr_collection::iterator pos, end = m_args.end(); + size_t i = idx; + for (pos = m_args.begin(); i > 0 && pos != end; ++pos) + --i; + + if (pos != end) + { + m_args.erase (pos); + assert(idx < m_argv.size() - 1); + m_argv.erase(m_argv.begin() + idx); + if (idx < m_args_quote_char.size()) + m_args_quote_char.erase(m_args_quote_char.begin() + idx); + } +} + +void +Args::SetArguments (size_t argc, const char **argv) +{ + // m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is + // no need to clear it here. + m_args.clear(); + m_args_quote_char.clear(); + + // First copy each string + for (size_t i=0; i<argc; ++i) + { + m_args.push_back (argv[i]); + if ((argv[i][0] == '\'') || (argv[i][0] == '"') || (argv[i][0] == '`')) + m_args_quote_char.push_back (argv[i][0]); + else + m_args_quote_char.push_back ('\0'); + } + + UpdateArgvFromArgs(); +} + +void +Args::SetArguments (const char **argv) +{ + // m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is + // no need to clear it here. + m_args.clear(); + m_args_quote_char.clear(); + + if (argv) + { + // First copy each string + for (size_t i=0; argv[i]; ++i) + { + m_args.push_back (argv[i]); + if ((argv[i][0] == '\'') || (argv[i][0] == '"') || (argv[i][0] == '`')) + m_args_quote_char.push_back (argv[i][0]); + else + m_args_quote_char.push_back ('\0'); + } + } + + UpdateArgvFromArgs(); +} + + +Error +Args::ParseOptions (Options &options) +{ + StreamString sstr; + Error error; + struct option *long_options = options.GetLongOptions(); + if (long_options == NULL) + { + error.SetErrorStringWithFormat("invalid long options"); + return error; + } + + for (int i=0; long_options[i].name != NULL; ++i) + { + if (long_options[i].flag == NULL) + { + if (isprint8(long_options[i].val)) + { + sstr << (char)long_options[i].val; + switch (long_options[i].has_arg) + { + default: + case no_argument: break; + case required_argument: sstr << ':'; break; + case optional_argument: sstr << "::"; break; + } + } + } + } +#ifdef __GLIBC__ + optind = 0; +#else + optreset = 1; + optind = 1; +#endif + int val; + while (1) + { + int long_options_index = -1; + val = ::getopt_long_only(GetArgumentCount(), + GetArgumentVector(), + sstr.GetData(), + long_options, + &long_options_index); + if (val == -1) + break; + + // Did we get an error? + if (val == '?') + { + error.SetErrorStringWithFormat("unknown or ambiguous option"); + break; + } + // The option auto-set itself + if (val == 0) + continue; + + ((Options *) &options)->OptionSeen (val); + + // Lookup the long option index + 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; + ++i) + { + if (long_options[i].val == val) + { + long_options_index = i; + break; + } + } + } + // Call the callback with the option + if (long_options_index >= 0) + { + error = options.SetOptionValue(long_options_index, + long_options[long_options_index].has_arg == no_argument ? NULL : optarg); + } + else + { + error.SetErrorStringWithFormat("invalid option with value '%i'", val); + } + if (error.Fail()) + break; + } + + // Update our ARGV now that get options has consumed all the options + m_argv.erase(m_argv.begin(), m_argv.begin() + optind); + UpdateArgsAfterOptionParsing (); + return error; +} + +void +Args::Clear () +{ + m_args.clear (); + m_argv.clear (); + m_args_quote_char.clear(); +} + +int32_t +Args::StringToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr) +{ + if (s && s[0]) + { + char *end = NULL; + const long sval = ::strtol (s, &end, base); + if (*end == '\0') + { + if (success_ptr) + *success_ptr = ((sval <= INT32_MAX) && (sval >= INT32_MIN)); + return (int32_t)sval; // All characters were used, return the result + } + } + if (success_ptr) *success_ptr = false; + return fail_value; +} + +uint32_t +Args::StringToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr) +{ + if (s && s[0]) + { + char *end = NULL; + const unsigned long uval = ::strtoul (s, &end, base); + if (*end == '\0') + { + if (success_ptr) + *success_ptr = (uval <= UINT32_MAX); + return (uint32_t)uval; // All characters were used, return the result + } + } + if (success_ptr) *success_ptr = false; + return fail_value; +} + + +int64_t +Args::StringToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr) +{ + if (s && s[0]) + { + char *end = NULL; + int64_t uval = ::strtoll (s, &end, base); + if (*end == '\0') + { + if (success_ptr) *success_ptr = true; + return uval; // All characters were used, return the result + } + } + if (success_ptr) *success_ptr = false; + return fail_value; +} + +uint64_t +Args::StringToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr) +{ + if (s && s[0]) + { + char *end = NULL; + uint64_t uval = ::strtoull (s, &end, base); + if (*end == '\0') + { + if (success_ptr) *success_ptr = true; + return uval; // All characters were used, return the result + } + } + if (success_ptr) *success_ptr = false; + return fail_value; +} + +lldb::addr_t +Args::StringToAddress (const ExecutionContext *exe_ctx, const char *s, lldb::addr_t fail_value, Error *error_ptr) +{ + bool error_set = false; + if (s && s[0]) + { + char *end = NULL; + lldb::addr_t addr = ::strtoull (s, &end, 0); + if (*end == '\0') + { + if (error_ptr) + error_ptr->Clear(); + return addr; // All characters were used, return the result + } + // Try base 16 with no prefix... + addr = ::strtoull (s, &end, 16); + if (*end == '\0') + { + if (error_ptr) + error_ptr->Clear(); + return addr; // All characters were used, return the result + } + + if (exe_ctx) + { + Target *target = exe_ctx->GetTargetPtr(); + if (target) + { + lldb::ValueObjectSP valobj_sp; + EvaluateExpressionOptions options; + options.SetCoerceToId(false); + options.SetUnwindOnError(true); + options.SetKeepInMemory(false); + options.SetRunOthers(true); + + ExecutionResults expr_result = target->EvaluateExpression(s, + exe_ctx->GetFramePtr(), + valobj_sp, + options); + + bool success = false; + if (expr_result == eExecutionCompleted) + { + // Get the address to watch. + addr = valobj_sp->GetValueAsUnsigned(fail_value, &success); + if (success) + { + if (error_ptr) + error_ptr->Clear(); + return addr; + } + else + { + if (error_ptr) + { + error_set = true; + error_ptr->SetErrorStringWithFormat("address expression \"%s\" resulted in a value whose type can't be converted to an address: %s", s, valobj_sp->GetTypeName().GetCString()); + } + } + + } + else + { + // Since the compiler can't handle things like "main + 12" we should + // try to do this for now. The compliler doesn't like adding offsets + // to function pointer types. + static RegularExpression g_symbol_plus_offset_regex("^(.*)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*$"); + RegularExpression::Match regex_match(3); + if (g_symbol_plus_offset_regex.Execute(s, ®ex_match)) + { + uint64_t offset = 0; + bool add = true; + std::string name; + std::string str; + if (regex_match.GetMatchAtIndex(s, 1, name)) + { + if (regex_match.GetMatchAtIndex(s, 2, str)) + { + add = str[0] == '+'; + + if (regex_match.GetMatchAtIndex(s, 3, str)) + { + offset = Args::StringToUInt64(str.c_str(), 0, 0, &success); + + if (success) + { + Error error; + addr = StringToAddress (exe_ctx, name.c_str(), LLDB_INVALID_ADDRESS, &error); + if (addr != LLDB_INVALID_ADDRESS) + { + if (add) + return addr + offset; + else + return addr - offset; + } + } + } + } + } + } + + if (error_ptr) + { + error_set = true; + error_ptr->SetErrorStringWithFormat("address expression \"%s\" evaluation failed", s); + } + } + } + } + } + if (error_ptr) + { + if (!error_set) + error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", s); + } + return fail_value; +} + +const char * +Args::StripSpaces (std::string &s, bool leading, bool trailing, bool return_null_if_empty) +{ + static const char *k_white_space = " \t\v"; + if (!s.empty()) + { + if (leading) + { + size_t pos = s.find_first_not_of (k_white_space); + if (pos == std::string::npos) + s.clear(); + else if (pos > 0) + s.erase(0, pos); + } + + if (trailing) + { + size_t rpos = s.find_last_not_of(k_white_space); + if (rpos != std::string::npos && rpos + 1 < s.size()) + s.erase(rpos + 1); + } + } + if (return_null_if_empty && s.empty()) + return NULL; + return s.c_str(); +} + +bool +Args::StringToBoolean (const char *s, bool fail_value, bool *success_ptr) +{ + if (s && s[0]) + { + if (::strcasecmp (s, "false") == 0 || + ::strcasecmp (s, "off") == 0 || + ::strcasecmp (s, "no") == 0 || + ::strcmp (s, "0") == 0) + { + if (success_ptr) + *success_ptr = true; + return false; + } + else + if (::strcasecmp (s, "true") == 0 || + ::strcasecmp (s, "on") == 0 || + ::strcasecmp (s, "yes") == 0 || + ::strcmp (s, "1") == 0) + { + if (success_ptr) *success_ptr = true; + return true; + } + } + if (success_ptr) *success_ptr = false; + return fail_value; +} + +const char * +Args::StringToVersion (const char *s, uint32_t &major, uint32_t &minor, uint32_t &update) +{ + major = UINT32_MAX; + minor = UINT32_MAX; + update = UINT32_MAX; + + if (s && s[0]) + { + char *pos = NULL; + unsigned long uval32 = ::strtoul (s, &pos, 0); + if (pos == s) + return s; + major = uval32; + if (*pos == '\0') + { + return pos; // Decoded major and got end of string + } + else if (*pos == '.') + { + const char *minor_cstr = pos + 1; + uval32 = ::strtoul (minor_cstr, &pos, 0); + if (pos == minor_cstr) + return pos; // Didn't get any digits for the minor version... + minor = uval32; + if (*pos == '.') + { + const char *update_cstr = pos + 1; + uval32 = ::strtoul (update_cstr, &pos, 0); + if (pos == update_cstr) + return pos; + update = uval32; + } + return pos; + } + } + return 0; +} + +const char * +Args::GetShellSafeArgument (const char *unsafe_arg, std::string &safe_arg) +{ + safe_arg.assign (unsafe_arg); + size_t prev_pos = 0; + while (prev_pos < safe_arg.size()) + { + // Escape spaces and quotes + size_t pos = safe_arg.find_first_of(" '\"", prev_pos); + if (pos != std::string::npos) + { + safe_arg.insert (pos, 1, '\\'); + prev_pos = pos + 2; + } + else + break; + } + return safe_arg.c_str(); +} + + +int64_t +Args::StringToOptionEnum (const char *s, OptionEnumValueElement *enum_values, int32_t fail_value, Error &error) +{ + if (enum_values) + { + if (s && s[0]) + { + for (int i = 0; enum_values[i].string_value != NULL ; i++) + { + if (strstr(enum_values[i].string_value, s) == enum_values[i].string_value) + { + error.Clear(); + return enum_values[i].value; + } + } + } + + StreamString strm; + strm.PutCString ("invalid enumeration value, valid values are: "); + for (int i = 0; enum_values[i].string_value != NULL; i++) + { + strm.Printf ("%s\"%s\"", + i > 0 ? ", " : "", + enum_values[i].string_value); + } + error.SetErrorString(strm.GetData()); + } + else + { + error.SetErrorString ("invalid enumeration argument"); + } + return fail_value; +} + +ScriptLanguage +Args::StringToScriptLanguage (const char *s, ScriptLanguage fail_value, bool *success_ptr) +{ + if (s && s[0]) + { + if ((::strcasecmp (s, "python") == 0) || + (::strcasecmp (s, "default") == 0 && eScriptLanguagePython == eScriptLanguageDefault)) + { + if (success_ptr) *success_ptr = true; + return eScriptLanguagePython; + } + if (::strcasecmp (s, "none")) + { + if (success_ptr) *success_ptr = true; + return eScriptLanguageNone; + } + } + if (success_ptr) *success_ptr = false; + return fail_value; +} + +Error +Args::StringToFormat +( + const char *s, + lldb::Format &format, + size_t *byte_size_ptr +) +{ + format = eFormatInvalid; + Error error; + + if (s && s[0]) + { + if (byte_size_ptr) + { + if (isdigit (s[0])) + { + char *format_char = NULL; + unsigned long byte_size = ::strtoul (s, &format_char, 0); + if (byte_size != ULONG_MAX) + *byte_size_ptr = byte_size; + s = format_char; + } + else + *byte_size_ptr = 0; + } + + const bool partial_match_ok = true; + if (!FormatManager::GetFormatFromCString (s, partial_match_ok, format)) + { + StreamString error_strm; + error_strm.Printf ("Invalid format character or name '%s'. Valid values are:\n", s); + for (Format f = eFormatDefault; f < kNumFormats; f = Format(f+1)) + { + char format_char = FormatManager::GetFormatAsFormatChar(f); + if (format_char) + error_strm.Printf ("'%c' or ", format_char); + + error_strm.Printf ("\"%s\"", FormatManager::GetFormatAsCString(f)); + error_strm.EOL(); + } + + if (byte_size_ptr) + error_strm.PutCString ("An optional byte size can precede the format character.\n"); + error.SetErrorString(error_strm.GetString().c_str()); + } + + if (error.Fail()) + return error; + } + else + { + error.SetErrorStringWithFormat("%s option string", s ? "empty" : "invalid"); + } + return error; +} + +lldb::Encoding +Args::StringToEncoding (const char *s, lldb::Encoding fail_value) +{ + if (s && s[0]) + { + if (strcmp(s, "uint") == 0) + return eEncodingUint; + else if (strcmp(s, "sint") == 0) + return eEncodingSint; + else if (strcmp(s, "ieee754") == 0) + return eEncodingIEEE754; + else if (strcmp(s, "vector") == 0) + return eEncodingVector; + } + return fail_value; +} + +uint32_t +Args::StringToGenericRegister (const char *s) +{ + if (s && s[0]) + { + if (strcmp(s, "pc") == 0) + return LLDB_REGNUM_GENERIC_PC; + else if (strcmp(s, "sp") == 0) + return LLDB_REGNUM_GENERIC_SP; + else if (strcmp(s, "fp") == 0) + return LLDB_REGNUM_GENERIC_FP; + else if (strcmp(s, "ra") == 0) + return LLDB_REGNUM_GENERIC_RA; + else if (strcmp(s, "flags") == 0) + return LLDB_REGNUM_GENERIC_FLAGS; + else if (strncmp(s, "arg", 3) == 0) + { + if (s[3] && s[4] == '\0') + { + switch (s[3]) + { + case '1': return LLDB_REGNUM_GENERIC_ARG1; + case '2': return LLDB_REGNUM_GENERIC_ARG2; + case '3': return LLDB_REGNUM_GENERIC_ARG3; + case '4': return LLDB_REGNUM_GENERIC_ARG4; + case '5': return LLDB_REGNUM_GENERIC_ARG5; + case '6': return LLDB_REGNUM_GENERIC_ARG6; + case '7': return LLDB_REGNUM_GENERIC_ARG7; + case '8': return LLDB_REGNUM_GENERIC_ARG8; + } + } + } + } + return LLDB_INVALID_REGNUM; +} + + +void +Args::LongestCommonPrefix (std::string &common_prefix) +{ + arg_sstr_collection::iterator pos, end = m_args.end(); + pos = m_args.begin(); + if (pos == end) + common_prefix.clear(); + else + common_prefix = (*pos); + + for (++pos; pos != end; ++pos) + { + size_t new_size = (*pos).size(); + + // First trim common_prefix if it is longer than the current element: + if (common_prefix.size() > new_size) + common_prefix.erase (new_size); + + // Then trim it at the first disparity: + + for (size_t i = 0; i < common_prefix.size(); i++) + { + if ((*pos)[i] != common_prefix[i]) + { + common_prefix.erase(i); + break; + } + } + + // If we've emptied the common prefix, we're done. + if (common_prefix.empty()) + break; + } +} + +size_t +Args::FindArgumentIndexForOption (struct 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); + size_t end = GetArgumentCount (); + size_t idx = 0; + while (idx < end) + { + if ((::strncmp (GetArgumentAtIndex (idx), short_buffer, strlen (short_buffer)) == 0) + || (::strncmp (GetArgumentAtIndex (idx), long_buffer, strlen (long_buffer)) == 0)) + { + return idx; + } + ++idx; + } + + return end; +} + +bool +Args::IsPositionalArgument (const char *arg) +{ + if (arg == NULL) + return false; + + bool is_positional = true; + char *cptr = (char *) arg; + + if (cptr[0] == '%') + { + ++cptr; + while (isdigit (cptr[0])) + ++cptr; + if (cptr[0] != '\0') + is_positional = false; + } + else + is_positional = false; + + return is_positional; +} + +void +Args::ParseAliasOptions (Options &options, + CommandReturnObject &result, + OptionArgVector *option_arg_vector, + std::string &raw_input_string) +{ + StreamString sstr; + int i; + struct option *long_options = options.GetLongOptions(); + + if (long_options == NULL) + { + result.AppendError ("invalid long options"); + result.SetStatus (eReturnStatusFailed); + return; + } + + for (i = 0; long_options[i].name != NULL; ++i) + { + if (long_options[i].flag == NULL) + { + sstr << (char) long_options[i].val; + switch (long_options[i].has_arg) + { + default: + case no_argument: + break; + case required_argument: + sstr << ":"; + break; + case optional_argument: + sstr << "::"; + break; + } + } + } + +#ifdef __GLIBC__ + optind = 0; +#else + optreset = 1; + optind = 1; +#endif + int val; + while (1) + { + int long_options_index = -1; + val = ::getopt_long_only (GetArgumentCount(), + GetArgumentVector(), + sstr.GetData(), + long_options, + &long_options_index); + + if (val == -1) + break; + + if (val == '?') + { + result.AppendError ("unknown or ambiguous option"); + result.SetStatus (eReturnStatusFailed); + break; + } + + if (val == 0) + continue; + + ((Options *) &options)->OptionSeen (val); + + // Look up the long option index + 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; + ++j) + { + if (long_options[j].val == val) + { + long_options_index = j; + break; + } + } + } + + // See if the option takes an argument, and see if one was supplied. + if (long_options_index >= 0) + { + StreamString option_str; + option_str.Printf ("-%c", val); + + switch (long_options[long_options_index].has_arg) + { + case no_argument: + option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), + OptionArgValue (no_argument, "<no-argument>"))); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + break; + case required_argument: + if (optarg != NULL) + { + option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), + OptionArgValue (required_argument, + std::string (optarg)))); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendErrorWithFormat ("Option '%s' is missing argument specifier.\n", + option_str.GetData()); + result.SetStatus (eReturnStatusFailed); + } + break; + case optional_argument: + if (optarg != NULL) + { + option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), + OptionArgValue (optional_argument, + std::string (optarg)))); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), + OptionArgValue (optional_argument, "<no-argument>"))); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + break; + default: + result.AppendErrorWithFormat ("error with options table; invalid value in has_arg field for option '%c'.\n", val); + result.SetStatus (eReturnStatusFailed); + break; + } + } + else + { + result.AppendErrorWithFormat ("Invalid option with value '%c'.\n", val); + result.SetStatus (eReturnStatusFailed); + } + + if (long_options_index >= 0) + { + // Find option in the argument list; also see if it was supposed to take an argument and if one was + // supplied. Remove option (and argument, if given) from the argument list. Also remove them from + // the raw_input_string, if one was passed in. + size_t idx = FindArgumentIndexForOption (long_options, long_options_index); + if (idx < GetArgumentCount()) + { + if (raw_input_string.size() > 0) + { + const char *tmp_arg = GetArgumentAtIndex (idx); + size_t pos = raw_input_string.find (tmp_arg); + if (pos != std::string::npos) + raw_input_string.erase (pos, strlen (tmp_arg)); + } + ReplaceArgumentAtIndex (idx, ""); + if ((long_options[long_options_index].has_arg != no_argument) + && (optarg != NULL) + && (idx+1 < GetArgumentCount()) + && (strcmp (optarg, GetArgumentAtIndex(idx+1)) == 0)) + { + if (raw_input_string.size() > 0) + { + const char *tmp_arg = GetArgumentAtIndex (idx+1); + size_t pos = raw_input_string.find (tmp_arg); + if (pos != std::string::npos) + raw_input_string.erase (pos, strlen (tmp_arg)); + } + ReplaceArgumentAtIndex (idx+1, ""); + } + } + } + + if (!result.Succeeded()) + break; + } +} + +void +Args::ParseArgsForCompletion +( + Options &options, + OptionElementVector &option_element_vector, + uint32_t cursor_index +) +{ + StreamString sstr; + struct option *long_options = options.GetLongOptions(); + option_element_vector.clear(); + + if (long_options == NULL) + { + return; + } + + // Leading : tells getopt to return a : for a missing option argument AND + // to suppress error messages. + + sstr << ":"; + for (int i = 0; long_options[i].name != NULL; ++i) + { + if (long_options[i].flag == NULL) + { + sstr << (char) long_options[i].val; + switch (long_options[i].has_arg) + { + default: + case no_argument: + break; + case required_argument: + sstr << ":"; + break; + case optional_argument: + sstr << "::"; + break; + } + } + } + +#ifdef __GLIBC__ + optind = 0; +#else + optreset = 1; + optind = 1; +#endif + opterr = 0; + + int val; + const OptionDefinition *opt_defs = options.GetDefinitions(); + + // Fooey... getopt_long_only permutes the GetArgumentVector to move the options to the front. + // So we have to build another Arg and pass that to getopt_long_only so it doesn't + // change the one we have. + + std::vector<const char *> dummy_vec (GetArgumentVector(), GetArgumentVector() + GetArgumentCount() + 1); + + bool failed_once = false; + uint32_t dash_dash_pos = -1; + + while (1) + { + bool missing_argument = false; + int long_options_index = -1; + + val = ::getopt_long_only (dummy_vec.size() - 1, + (char *const *) &dummy_vec.front(), + sstr.GetData(), + long_options, + &long_options_index); + + if (val == -1) + { + // When we're completing a "--" which is the last option on line, + if (failed_once) + break; + + failed_once = true; + + // If this is a bare "--" we mark it as such so we can complete it successfully later. + // Handling the "--" is a little tricky, since that may mean end of options or arguments, or the + // user might want to complete options by long name. I make this work by checking whether the + // cursor is in the "--" argument, and if so I assume we're completing the long option, otherwise + // I let it pass to getopt_long_only which will terminate the option parsing. + // Note, in either case we continue parsing the line so we can figure out what other options + // were passed. This will be useful when we come to restricting completions based on what other + // options we've seen on the line. + + if (optind < dummy_vec.size() - 1 + && (strcmp (dummy_vec[optind-1], "--") == 0)) + { + dash_dash_pos = optind - 1; + if (optind - 1 == cursor_index) + { + option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDoubleDash, optind - 1, + OptionArgElement::eBareDoubleDash)); + continue; + } + else + break; + } + else + break; + } + else if (val == '?') + { + option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, optind - 1, + OptionArgElement::eUnrecognizedArg)); + continue; + } + else if (val == 0) + { + continue; + } + else if (val == ':') + { + // This is a missing argument. + val = optopt; + missing_argument = true; + } + + ((Options *) &options)->OptionSeen (val); + + // Look up the long option index + 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; + ++j) + { + if (long_options[j].val == val) + { + long_options_index = j; + break; + } + } + } + + // See if the option takes an argument, and see if one was supplied. + if (long_options_index >= 0) + { + int opt_defs_index = -1; + for (int i = 0; ; i++) + { + if (opt_defs[i].short_option == 0) + break; + else if (opt_defs[i].short_option == val) + { + opt_defs_index = i; + break; + } + } + + switch (long_options[long_options_index].has_arg) + { + case no_argument: + option_element_vector.push_back (OptionArgElement (opt_defs_index, optind - 1, 0)); + break; + case required_argument: + if (optarg != NULL) + { + int arg_index; + if (missing_argument) + arg_index = -1; + else + arg_index = optind - 1; + + option_element_vector.push_back (OptionArgElement (opt_defs_index, optind - 2, arg_index)); + } + else + { + option_element_vector.push_back (OptionArgElement (opt_defs_index, optind - 1, -1)); + } + break; + case optional_argument: + if (optarg != NULL) + { + option_element_vector.push_back (OptionArgElement (opt_defs_index, optind - 2, optind - 1)); + } + else + { + option_element_vector.push_back (OptionArgElement (opt_defs_index, optind - 2, optind - 1)); + } + break; + default: + // The options table is messed up. Here we'll just continue + option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, optind - 1, + OptionArgElement::eUnrecognizedArg)); + break; + } + } + else + { + option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, optind - 1, + OptionArgElement::eUnrecognizedArg)); + } + } + + // Finally we have to handle the case where the cursor index points at a single "-". We want to mark that in + // the option_element_vector, but only if it is not after the "--". But it turns out that getopt_long_only just ignores + // an isolated "-". So we have to look it up by hand here. We only care if it is AT the cursor position. + + if ((dash_dash_pos == -1 || cursor_index < dash_dash_pos) + && strcmp (GetArgumentAtIndex(cursor_index), "-") == 0) + { + option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDash, cursor_index, + OptionArgElement::eBareDash)); + + } +} + +void +Args::EncodeEscapeSequences (const char *src, std::string &dst) +{ + dst.clear(); + if (src) + { + for (const char *p = src; *p != '\0'; ++p) + { + size_t non_special_chars = ::strcspn (p, "\\"); + if (non_special_chars > 0) + { + dst.append(p, non_special_chars); + p += non_special_chars; + if (*p == '\0') + break; + } + + if (*p == '\\') + { + ++p; // skip the slash + switch (*p) + { + case 'a' : dst.append(1, '\a'); break; + case 'b' : dst.append(1, '\b'); break; + case 'f' : dst.append(1, '\f'); break; + case 'n' : dst.append(1, '\n'); break; + case 'r' : dst.append(1, '\r'); break; + case 't' : dst.append(1, '\t'); break; + case 'v' : dst.append(1, '\v'); break; + case '\\': dst.append(1, '\\'); break; + case '\'': dst.append(1, '\''); break; + case '"' : dst.append(1, '"'); break; + case '0' : + // 1 to 3 octal chars + { + // Make a string that can hold onto the initial zero char, + // up to 3 octal digits, and a terminating NULL. + char oct_str[5] = { '\0', '\0', '\0', '\0', '\0' }; + + int i; + for (i=0; (p[i] >= '0' && p[i] <= '7') && i<4; ++i) + oct_str[i] = p[i]; + + // We don't want to consume the last octal character since + // the main for loop will do this for us, so we advance p by + // one less than i (even if i is zero) + p += i - 1; + unsigned long octal_value = ::strtoul (oct_str, NULL, 8); + if (octal_value <= UINT8_MAX) + { + dst.append(1, (char)octal_value); + } + } + break; + + case 'x': + // hex number in the format + if (isxdigit(p[1])) + { + ++p; // Skip the 'x' + + // Make a string that can hold onto two hex chars plus a + // NULL terminator + char hex_str[3] = { *p, '\0', '\0' }; + if (isxdigit(p[1])) + { + ++p; // Skip the first of the two hex chars + hex_str[1] = *p; + } + + unsigned long hex_value = strtoul (hex_str, NULL, 16); + if (hex_value <= UINT8_MAX) + dst.append (1, (char)hex_value); + } + else + { + dst.append(1, 'x'); + } + break; + + default: + // Just desensitize any other character by just printing what + // came after the '\' + dst.append(1, *p); + break; + + } + } + } + } +} + + +void +Args::ExpandEscapedCharacters (const char *src, std::string &dst) +{ + dst.clear(); + if (src) + { + for (const char *p = src; *p != '\0'; ++p) + { + if (isprint8(*p)) + dst.append(1, *p); + else + { + switch (*p) + { + case '\a': dst.append("\\a"); break; + case '\b': dst.append("\\b"); break; + case '\f': dst.append("\\f"); break; + case '\n': dst.append("\\n"); break; + case '\r': dst.append("\\r"); break; + case '\t': dst.append("\\t"); break; + case '\v': dst.append("\\v"); break; + case '\'': dst.append("\\'"); break; + case '"': dst.append("\\\""); break; + case '\\': dst.append("\\\\"); break; + default: + { + // Just encode as octal + dst.append("\\0"); + char octal_str[32]; + snprintf(octal_str, sizeof(octal_str), "%o", *p); + dst.append(octal_str); + } + break; + } + } + } + } +} + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandHistory.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandHistory.cpp new file mode 100644 index 0000000..33971e3 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandHistory.cpp @@ -0,0 +1,143 @@ +//===-- CommandHistory.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/CommandHistory.h" +#include "lldb/Interpreter/Args.h" + +using namespace lldb; +using namespace lldb_private; + + +CommandHistory::CommandHistory () : + m_mutex(Mutex::eMutexTypeRecursive), + m_history() +{} + +CommandHistory::~CommandHistory () +{} + +size_t +CommandHistory::GetSize () const +{ + Mutex::Locker locker(m_mutex); + return m_history.size(); +} + +bool +CommandHistory::IsEmpty () const +{ + Mutex::Locker locker(m_mutex); + return m_history.empty(); +} + +const char* +CommandHistory::FindString (const char* input_str) const +{ + Mutex::Locker locker(m_mutex); + if (!input_str) + return NULL; + if (input_str[0] != g_repeat_char) + return NULL; + if (input_str[1] == '-') + { + bool success; + size_t idx = Args::StringToUInt32 (input_str+2, 0, 0, &success); + if (!success) + return NULL; + if (idx > m_history.size()) + return NULL; + idx = m_history.size() - idx; + return m_history[idx].c_str(); + + } + else if (input_str[1] == g_repeat_char) + { + if (m_history.empty()) + return NULL; + else + return m_history.back().c_str(); + } + else + { + bool success; + uint32_t idx = Args::StringToUInt32 (input_str+1, 0, 0, &success); + if (!success) + return NULL; + if (idx >= m_history.size()) + return NULL; + return m_history[idx].c_str(); + } +} + +const char* +CommandHistory::GetStringAtIndex (size_t idx) const +{ + Mutex::Locker locker(m_mutex); + if (idx < m_history.size()) + return m_history[idx].c_str(); + return NULL; +} + +const char* +CommandHistory::operator [] (size_t idx) const +{ + return GetStringAtIndex(idx); +} + +const char* +CommandHistory::GetRecentmostString () const +{ + Mutex::Locker locker(m_mutex); + if (m_history.empty()) + return NULL; + return m_history.back().c_str(); +} + +void +CommandHistory::AppendString (const std::string& str, + bool reject_if_dupe) +{ + Mutex::Locker locker(m_mutex); + if (reject_if_dupe) + { + if (!m_history.empty()) + { + if (str == m_history.back()) + return; + } + } + m_history.push_back(std::string(str)); +} + +void +CommandHistory::Clear () +{ + Mutex::Locker locker(m_mutex); + m_history.clear(); +} + +void +CommandHistory::Dump (Stream& stream, + size_t start_idx, + size_t stop_idx) const +{ + Mutex::Locker locker(m_mutex); + stop_idx = std::min(stop_idx, m_history.size() - 1); + for (size_t counter = start_idx; + counter <= stop_idx; + counter++) + { + const std::string hist_item = m_history[counter]; + if (!hist_item.empty()) + { + stream.Indent(); + stream.Printf ("%4zu: %s\n", counter, hist_item.c_str()); + } + } +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp new file mode 100644 index 0000000..db2f2fa --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp @@ -0,0 +1,2882 @@ +//===-- CommandInterpreter.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/lldb-python.h" + +#include <string> +#include <vector> + +#include <getopt.h> +#include <stdlib.h> + +#include "CommandObjectScript.h" +#include "lldb/Interpreter/CommandObjectRegexCommand.h" + +#include "../Commands/CommandObjectApropos.h" +#include "../Commands/CommandObjectArgs.h" +#include "../Commands/CommandObjectBreakpoint.h" +#include "../Commands/CommandObjectDisassemble.h" +#include "../Commands/CommandObjectExpression.h" +#include "../Commands/CommandObjectFrame.h" +#include "../Commands/CommandObjectHelp.h" +#include "../Commands/CommandObjectLog.h" +#include "../Commands/CommandObjectMemory.h" +#include "../Commands/CommandObjectPlatform.h" +#include "../Commands/CommandObjectPlugin.h" +#include "../Commands/CommandObjectProcess.h" +#include "../Commands/CommandObjectQuit.h" +#include "../Commands/CommandObjectRegister.h" +#include "../Commands/CommandObjectSettings.h" +#include "../Commands/CommandObjectSource.h" +#include "../Commands/CommandObjectCommands.h" +#include "../Commands/CommandObjectSyntax.h" +#include "../Commands/CommandObjectTarget.h" +#include "../Commands/CommandObjectThread.h" +#include "../Commands/CommandObjectType.h" +#include "../Commands/CommandObjectVersion.h" +#include "../Commands/CommandObjectWatchpoint.h" + + +#include "lldb/Core/Debugger.h" +#include "lldb/Core/InputReader.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/Timer.h" + +#include "lldb/Host/Host.h" + +#include "lldb/Interpreter/Args.h" +#include "lldb/Interpreter/CommandCompletions.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/Options.h" +#include "lldb/Interpreter/ScriptInterpreterNone.h" +#include "lldb/Interpreter/ScriptInterpreterPython.h" + + +#include "lldb/Target/Process.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/TargetList.h" + +#include "lldb/Utility/CleanUp.h" + +using namespace lldb; +using namespace lldb_private; + + +static PropertyDefinition +g_properties[] = +{ + { "expand-regex-aliases", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, regular expression alias commands will show the expanded command that will be executed. This can be used to debug new regular expression alias commands." }, + { "prompt-on-quit", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will prompt you before quitting if there are any live processes being debugged. If false, LLDB will quit without asking in any case." }, + { "stop-command-source-on-error", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will stop running a 'command source' script upon encountering an error." }, + { NULL , OptionValue::eTypeInvalid, true, 0 , NULL, NULL, NULL } +}; + +enum +{ + ePropertyExpandRegexAliases = 0, + ePropertyPromptOnQuit = 1, + ePropertyStopCmdSourceOnError = 2 +}; + +ConstString & +CommandInterpreter::GetStaticBroadcasterClass () +{ + static ConstString class_name ("lldb.commandInterpreter"); + return class_name; +} + +CommandInterpreter::CommandInterpreter +( + Debugger &debugger, + ScriptLanguage script_language, + bool synchronous_execution +) : + Broadcaster (&debugger, "lldb.command-interpreter"), + Properties(OptionValuePropertiesSP(new OptionValueProperties(ConstString("interpreter")))), + m_debugger (debugger), + m_synchronous_execution (synchronous_execution), + m_skip_lldbinit_files (false), + m_skip_app_init_files (false), + m_script_interpreter_ap (), + m_comment_char ('#'), + m_batch_command_mode (false), + m_truncation_warning(eNoTruncation), + m_command_source_depth (0) +{ + debugger.SetScriptLanguage (script_language); + SetEventName (eBroadcastBitThreadShouldExit, "thread-should-exit"); + SetEventName (eBroadcastBitResetPrompt, "reset-prompt"); + SetEventName (eBroadcastBitQuitCommandReceived, "quit"); + CheckInWithManager (); + m_collection_sp->Initialize (g_properties); +} + +bool +CommandInterpreter::GetExpandRegexAliases () const +{ + const uint32_t idx = ePropertyExpandRegexAliases; + return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); +} + +bool +CommandInterpreter::GetPromptOnQuit () const +{ + const uint32_t idx = ePropertyPromptOnQuit; + return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); +} + +bool +CommandInterpreter::GetStopCmdSourceOnError () const +{ + const uint32_t idx = ePropertyStopCmdSourceOnError; + return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); +} + +void +CommandInterpreter::Initialize () +{ + Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); + + CommandReturnObject result; + + LoadCommandDictionary (); + + // Set up some initial aliases. + CommandObjectSP cmd_obj_sp = GetCommandSPExact ("quit", false); + if (cmd_obj_sp) + { + AddAlias ("q", cmd_obj_sp); + AddAlias ("exit", cmd_obj_sp); + } + + cmd_obj_sp = GetCommandSPExact ("_regexp-attach",false); + if (cmd_obj_sp) + { + AddAlias ("attach", cmd_obj_sp); + } + + cmd_obj_sp = GetCommandSPExact ("process detach",false); + if (cmd_obj_sp) + { + AddAlias ("detach", cmd_obj_sp); + } + + cmd_obj_sp = GetCommandSPExact ("process continue", false); + if (cmd_obj_sp) + { + AddAlias ("c", cmd_obj_sp); + AddAlias ("continue", cmd_obj_sp); + } + + cmd_obj_sp = GetCommandSPExact ("_regexp-break",false); + if (cmd_obj_sp) + AddAlias ("b", cmd_obj_sp); + + cmd_obj_sp = GetCommandSPExact ("_regexp-tbreak",false); + if (cmd_obj_sp) + AddAlias ("tbreak", cmd_obj_sp); + + cmd_obj_sp = GetCommandSPExact ("thread step-inst", false); + if (cmd_obj_sp) + { + AddAlias ("stepi", cmd_obj_sp); + AddAlias ("si", cmd_obj_sp); + } + + cmd_obj_sp = GetCommandSPExact ("thread step-inst-over", false); + if (cmd_obj_sp) + { + AddAlias ("nexti", cmd_obj_sp); + AddAlias ("ni", cmd_obj_sp); + } + + cmd_obj_sp = GetCommandSPExact ("thread step-in", false); + if (cmd_obj_sp) + { + AddAlias ("s", cmd_obj_sp); + AddAlias ("step", cmd_obj_sp); + } + + cmd_obj_sp = GetCommandSPExact ("thread step-over", false); + if (cmd_obj_sp) + { + AddAlias ("n", cmd_obj_sp); + AddAlias ("next", cmd_obj_sp); + } + + cmd_obj_sp = GetCommandSPExact ("thread step-out", false); + if (cmd_obj_sp) + { + AddAlias ("finish", cmd_obj_sp); + } + + cmd_obj_sp = GetCommandSPExact ("frame select", false); + if (cmd_obj_sp) + { + AddAlias ("f", cmd_obj_sp); + } + + cmd_obj_sp = GetCommandSPExact ("thread select", false); + if (cmd_obj_sp) + { + AddAlias ("t", cmd_obj_sp); + } + + cmd_obj_sp = GetCommandSPExact ("_regexp-list", false); + if (cmd_obj_sp) + { + AddAlias ("l", cmd_obj_sp); + AddAlias ("list", cmd_obj_sp); + } + + cmd_obj_sp = GetCommandSPExact ("_regexp-env", false); + if (cmd_obj_sp) + { + AddAlias ("env", cmd_obj_sp); + } + + cmd_obj_sp = GetCommandSPExact ("memory read", false); + if (cmd_obj_sp) + AddAlias ("x", cmd_obj_sp); + + cmd_obj_sp = GetCommandSPExact ("_regexp-up", false); + if (cmd_obj_sp) + AddAlias ("up", cmd_obj_sp); + + cmd_obj_sp = GetCommandSPExact ("_regexp-down", false); + if (cmd_obj_sp) + AddAlias ("down", cmd_obj_sp); + + cmd_obj_sp = GetCommandSPExact ("_regexp-display", false); + if (cmd_obj_sp) + AddAlias ("display", cmd_obj_sp); + + cmd_obj_sp = GetCommandSPExact ("disassemble", false); + if (cmd_obj_sp) + AddAlias ("dis", cmd_obj_sp); + + cmd_obj_sp = GetCommandSPExact ("disassemble", false); + if (cmd_obj_sp) + AddAlias ("di", cmd_obj_sp); + + + + cmd_obj_sp = GetCommandSPExact ("_regexp-undisplay", false); + if (cmd_obj_sp) + AddAlias ("undisplay", cmd_obj_sp); + + cmd_obj_sp = GetCommandSPExact ("_regexp-bt", false); + if (cmd_obj_sp) + AddAlias ("bt", cmd_obj_sp); + + cmd_obj_sp = GetCommandSPExact ("target create", false); + if (cmd_obj_sp) + AddAlias ("file", cmd_obj_sp); + + cmd_obj_sp = GetCommandSPExact ("target modules", false); + if (cmd_obj_sp) + AddAlias ("image", cmd_obj_sp); + + + OptionArgVectorSP alias_arguments_vector_sp (new OptionArgVector); + + cmd_obj_sp = GetCommandSPExact ("expression", false); + if (cmd_obj_sp) + { + ProcessAliasOptionsArgs (cmd_obj_sp, "--", alias_arguments_vector_sp); + AddAlias ("p", cmd_obj_sp); + AddAlias ("print", cmd_obj_sp); + AddAlias ("call", cmd_obj_sp); + AddOrReplaceAliasOptions ("p", alias_arguments_vector_sp); + AddOrReplaceAliasOptions ("print", alias_arguments_vector_sp); + AddOrReplaceAliasOptions ("call", alias_arguments_vector_sp); + + alias_arguments_vector_sp.reset (new OptionArgVector); + ProcessAliasOptionsArgs (cmd_obj_sp, "-O -- ", alias_arguments_vector_sp); + AddAlias ("po", cmd_obj_sp); + AddOrReplaceAliasOptions ("po", alias_arguments_vector_sp); + } + + cmd_obj_sp = GetCommandSPExact ("process kill", false); + if (cmd_obj_sp) + { + AddAlias ("kill", cmd_obj_sp); + } + + cmd_obj_sp = GetCommandSPExact ("process launch", false); + if (cmd_obj_sp) + { + alias_arguments_vector_sp.reset (new OptionArgVector); +#if defined (__arm__) + ProcessAliasOptionsArgs (cmd_obj_sp, "--", alias_arguments_vector_sp); +#else + ProcessAliasOptionsArgs (cmd_obj_sp, "--shell=/bin/bash --", alias_arguments_vector_sp); +#endif + AddAlias ("r", cmd_obj_sp); + AddAlias ("run", cmd_obj_sp); + AddOrReplaceAliasOptions ("r", alias_arguments_vector_sp); + AddOrReplaceAliasOptions ("run", alias_arguments_vector_sp); + } + + cmd_obj_sp = GetCommandSPExact ("target symbols add", false); + if (cmd_obj_sp) + { + AddAlias ("add-dsym", cmd_obj_sp); + } + + cmd_obj_sp = GetCommandSPExact ("breakpoint set", false); + if (cmd_obj_sp) + { + alias_arguments_vector_sp.reset (new OptionArgVector); + ProcessAliasOptionsArgs (cmd_obj_sp, "--func-regex %1", alias_arguments_vector_sp); + AddAlias ("rbreak", cmd_obj_sp); + AddOrReplaceAliasOptions("rbreak", alias_arguments_vector_sp); + } +} + +const char * +CommandInterpreter::ProcessEmbeddedScriptCommands (const char *arg) +{ + // This function has not yet been implemented. + + // Look for any embedded script command + // If found, + // get interpreter object from the command dictionary, + // call execute_one_command on it, + // get the results as a string, + // substitute that string for current stuff. + + return arg; +} + + +void +CommandInterpreter::LoadCommandDictionary () +{ + Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); + + lldb::ScriptLanguage script_language = m_debugger.GetScriptLanguage(); + + m_command_dict["apropos"] = CommandObjectSP (new CommandObjectApropos (*this)); + m_command_dict["breakpoint"]= CommandObjectSP (new CommandObjectMultiwordBreakpoint (*this)); + m_command_dict["command"] = CommandObjectSP (new CommandObjectMultiwordCommands (*this)); + m_command_dict["disassemble"] = CommandObjectSP (new CommandObjectDisassemble (*this)); + m_command_dict["expression"]= CommandObjectSP (new CommandObjectExpression (*this)); + m_command_dict["frame"] = CommandObjectSP (new CommandObjectMultiwordFrame (*this)); + m_command_dict["help"] = CommandObjectSP (new CommandObjectHelp (*this)); + m_command_dict["log"] = CommandObjectSP (new CommandObjectLog (*this)); + m_command_dict["memory"] = CommandObjectSP (new CommandObjectMemory (*this)); + m_command_dict["platform"] = CommandObjectSP (new CommandObjectPlatform (*this)); + m_command_dict["plugin"] = CommandObjectSP (new CommandObjectPlugin (*this)); + m_command_dict["process"] = CommandObjectSP (new CommandObjectMultiwordProcess (*this)); + m_command_dict["quit"] = CommandObjectSP (new CommandObjectQuit (*this)); + m_command_dict["register"] = CommandObjectSP (new CommandObjectRegister (*this)); + m_command_dict["script"] = CommandObjectSP (new CommandObjectScript (*this, script_language)); + m_command_dict["settings"] = CommandObjectSP (new CommandObjectMultiwordSettings (*this)); + m_command_dict["source"] = CommandObjectSP (new CommandObjectMultiwordSource (*this)); + m_command_dict["target"] = CommandObjectSP (new CommandObjectMultiwordTarget (*this)); + m_command_dict["thread"] = CommandObjectSP (new CommandObjectMultiwordThread (*this)); + m_command_dict["type"] = CommandObjectSP (new CommandObjectType (*this)); + m_command_dict["version"] = CommandObjectSP (new CommandObjectVersion (*this)); + m_command_dict["watchpoint"]= CommandObjectSP (new CommandObjectMultiwordWatchpoint (*this)); + + const char *break_regexes[][2] = {{"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", "breakpoint set --file '%1' --line %2"}, + {"^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1"}, + {"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1"}, + {"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$", "breakpoint set --name '%1'"}, + {"^(-.*)$", "breakpoint set %1"}, + {"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%2' --shlib '%1'"}, + {"^\\&(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%1' --skip-prologue=0"}, + {"^(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%1'"}}; + + size_t num_regexes = sizeof break_regexes/sizeof(char *[2]); + + std::unique_ptr<CommandObjectRegexCommand> + break_regex_cmd_ap(new CommandObjectRegexCommand (*this, + "_regexp-break", + "Set a breakpoint using a regular expression to specify the location, where <linenum> is in decimal and <address> is in hex.", + "_regexp-break [<filename>:<linenum>]\n_regexp-break [<linenum>]\n_regexp-break [<address>]\n_regexp-break <...>", + 2, + CommandCompletions::eSymbolCompletion | + CommandCompletions::eSourceFileCompletion)); + + if (break_regex_cmd_ap.get()) + { + bool success = true; + for (size_t i = 0; i < num_regexes; i++) + { + success = break_regex_cmd_ap->AddRegexCommand (break_regexes[i][0], break_regexes[i][1]); + if (!success) + break; + } + success = break_regex_cmd_ap->AddRegexCommand("^$", "breakpoint list --full"); + + if (success) + { + CommandObjectSP break_regex_cmd_sp(break_regex_cmd_ap.release()); + m_command_dict[break_regex_cmd_sp->GetCommandName ()] = break_regex_cmd_sp; + } + } + + std::unique_ptr<CommandObjectRegexCommand> + tbreak_regex_cmd_ap(new CommandObjectRegexCommand (*this, + "_regexp-tbreak", + "Set a one shot breakpoint using a regular expression to specify the location, where <linenum> is in decimal and <address> is in hex.", + "_regexp-tbreak [<filename>:<linenum>]\n_regexp-break [<linenum>]\n_regexp-break [<address>]\n_regexp-break <...>", + 2, + CommandCompletions::eSymbolCompletion | + CommandCompletions::eSourceFileCompletion)); + + if (tbreak_regex_cmd_ap.get()) + { + bool success = true; + for (size_t i = 0; i < num_regexes; i++) + { + // If you add a resultant command string longer than 1024 characters be sure to increase the size of this buffer. + char buffer[1024]; + int num_printed = snprintf(buffer, 1024, "%s %s", break_regexes[i][1], "-o"); + assert (num_printed < 1024); + success = tbreak_regex_cmd_ap->AddRegexCommand (break_regexes[i][0], buffer); + if (!success) + break; + } + success = tbreak_regex_cmd_ap->AddRegexCommand("^$", "breakpoint list --full"); + + if (success) + { + CommandObjectSP tbreak_regex_cmd_sp(tbreak_regex_cmd_ap.release()); + m_command_dict[tbreak_regex_cmd_sp->GetCommandName ()] = tbreak_regex_cmd_sp; + } + } + + std::unique_ptr<CommandObjectRegexCommand> + attach_regex_cmd_ap(new CommandObjectRegexCommand (*this, + "_regexp-attach", + "Attach to a process id if in decimal, otherwise treat the argument as a process name to attach to.", + "_regexp-attach [<pid>]\n_regexp-attach [<process-name>]", + 2)); + if (attach_regex_cmd_ap.get()) + { + if (attach_regex_cmd_ap->AddRegexCommand("^([0-9]+)[[:space:]]*$", "process attach --pid %1") && + attach_regex_cmd_ap->AddRegexCommand("^(-.*|.* -.*)$", "process attach %1") && // Any options that are specified get passed to 'process attach' + attach_regex_cmd_ap->AddRegexCommand("^(.+)$", "process attach --name '%1'") && + attach_regex_cmd_ap->AddRegexCommand("^$", "process attach")) + { + CommandObjectSP attach_regex_cmd_sp(attach_regex_cmd_ap.release()); + m_command_dict[attach_regex_cmd_sp->GetCommandName ()] = attach_regex_cmd_sp; + } + } + + std::unique_ptr<CommandObjectRegexCommand> + down_regex_cmd_ap(new CommandObjectRegexCommand (*this, + "_regexp-down", + "Go down \"n\" frames in the stack (1 frame by default).", + "_regexp-down [n]", 2)); + if (down_regex_cmd_ap.get()) + { + if (down_regex_cmd_ap->AddRegexCommand("^$", "frame select -r -1") && + down_regex_cmd_ap->AddRegexCommand("^([0-9]+)$", "frame select -r -%1")) + { + CommandObjectSP down_regex_cmd_sp(down_regex_cmd_ap.release()); + m_command_dict[down_regex_cmd_sp->GetCommandName ()] = down_regex_cmd_sp; + } + } + + std::unique_ptr<CommandObjectRegexCommand> + up_regex_cmd_ap(new CommandObjectRegexCommand (*this, + "_regexp-up", + "Go up \"n\" frames in the stack (1 frame by default).", + "_regexp-up [n]", 2)); + if (up_regex_cmd_ap.get()) + { + if (up_regex_cmd_ap->AddRegexCommand("^$", "frame select -r 1") && + up_regex_cmd_ap->AddRegexCommand("^([0-9]+)$", "frame select -r %1")) + { + CommandObjectSP up_regex_cmd_sp(up_regex_cmd_ap.release()); + m_command_dict[up_regex_cmd_sp->GetCommandName ()] = up_regex_cmd_sp; + } + } + + std::unique_ptr<CommandObjectRegexCommand> + display_regex_cmd_ap(new CommandObjectRegexCommand (*this, + "_regexp-display", + "Add an expression evaluation stop-hook.", + "_regexp-display expression", 2)); + if (display_regex_cmd_ap.get()) + { + if (display_regex_cmd_ap->AddRegexCommand("^(.+)$", "target stop-hook add -o \"expr -- %1\"")) + { + CommandObjectSP display_regex_cmd_sp(display_regex_cmd_ap.release()); + m_command_dict[display_regex_cmd_sp->GetCommandName ()] = display_regex_cmd_sp; + } + } + + std::unique_ptr<CommandObjectRegexCommand> + undisplay_regex_cmd_ap(new CommandObjectRegexCommand (*this, + "_regexp-undisplay", + "Remove an expression evaluation stop-hook.", + "_regexp-undisplay stop-hook-number", 2)); + if (undisplay_regex_cmd_ap.get()) + { + if (undisplay_regex_cmd_ap->AddRegexCommand("^([0-9]+)$", "target stop-hook delete %1")) + { + CommandObjectSP undisplay_regex_cmd_sp(undisplay_regex_cmd_ap.release()); + m_command_dict[undisplay_regex_cmd_sp->GetCommandName ()] = undisplay_regex_cmd_sp; + } + } + + std::unique_ptr<CommandObjectRegexCommand> + connect_gdb_remote_cmd_ap(new CommandObjectRegexCommand (*this, + "gdb-remote", + "Connect to a remote GDB server. If no hostname is provided, localhost is assumed.", + "gdb-remote [<hostname>:]<portnum>", 2)); + if (connect_gdb_remote_cmd_ap.get()) + { + if (connect_gdb_remote_cmd_ap->AddRegexCommand("^([^:]+:[[:digit:]]+)$", "process connect --plugin gdb-remote connect://%1") && + connect_gdb_remote_cmd_ap->AddRegexCommand("^([[:digit:]]+)$", "process connect --plugin gdb-remote connect://localhost:%1")) + { + CommandObjectSP command_sp(connect_gdb_remote_cmd_ap.release()); + m_command_dict[command_sp->GetCommandName ()] = command_sp; + } + } + + std::unique_ptr<CommandObjectRegexCommand> + connect_kdp_remote_cmd_ap(new CommandObjectRegexCommand (*this, + "kdp-remote", + "Connect to a remote KDP server. udp port 41139 is the default port number.", + "kdp-remote <hostname>[:<portnum>]", 2)); + if (connect_kdp_remote_cmd_ap.get()) + { + if (connect_kdp_remote_cmd_ap->AddRegexCommand("^([^:]+:[[:digit:]]+)$", "process connect --plugin kdp-remote udp://%1") && + connect_kdp_remote_cmd_ap->AddRegexCommand("^(.+)$", "process connect --plugin kdp-remote udp://%1:41139")) + { + CommandObjectSP command_sp(connect_kdp_remote_cmd_ap.release()); + m_command_dict[command_sp->GetCommandName ()] = command_sp; + } + } + + std::unique_ptr<CommandObjectRegexCommand> + bt_regex_cmd_ap(new CommandObjectRegexCommand (*this, + "_regexp-bt", + "Show a backtrace. An optional argument is accepted; if that argument is a number, it specifies the number of frames to display. If that argument is 'all', full backtraces of all threads are displayed.", + "bt [<digit>|all]", 2)); + if (bt_regex_cmd_ap.get()) + { + // accept but don't document "bt -c <number>" -- before bt was a regex command if you wanted to backtrace + // three frames you would do "bt -c 3" but the intention is to have this emulate the gdb "bt" command and + // so now "bt 3" is the preferred form, in line with gdb. + if (bt_regex_cmd_ap->AddRegexCommand("^([[:digit:]]+)$", "thread backtrace -c %1") && + bt_regex_cmd_ap->AddRegexCommand("^-c ([[:digit:]]+)$", "thread backtrace -c %1") && + bt_regex_cmd_ap->AddRegexCommand("^all$", "thread backtrace all") && + bt_regex_cmd_ap->AddRegexCommand("^$", "thread backtrace")) + { + CommandObjectSP command_sp(bt_regex_cmd_ap.release()); + m_command_dict[command_sp->GetCommandName ()] = command_sp; + } + } + + std::unique_ptr<CommandObjectRegexCommand> + list_regex_cmd_ap(new CommandObjectRegexCommand (*this, + "_regexp-list", + "Implements the GDB 'list' command in all of its forms except FILE:FUNCTION and maps them to the appropriate 'source list' commands.", + "_regexp-list [<line>]\n_regexp-attach [<file>:<line>]\n_regexp-attach [<file>:<line>]", + 2, + CommandCompletions::eSourceFileCompletion)); + if (list_regex_cmd_ap.get()) + { + if (list_regex_cmd_ap->AddRegexCommand("^([0-9]+)[[:space:]]*$", "source list --line %1") && + list_regex_cmd_ap->AddRegexCommand("^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", "source list --file '%1' --line %2") && + list_regex_cmd_ap->AddRegexCommand("^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "source list --address %1") && + list_regex_cmd_ap->AddRegexCommand("^-[[:space:]]*$", "source list --reverse") && + list_regex_cmd_ap->AddRegexCommand("^-([[:digit:]]+)[[:space:]]*$", "source list --reverse --count %1") && + list_regex_cmd_ap->AddRegexCommand("^(.+)$", "source list --name \"%1\"") && + list_regex_cmd_ap->AddRegexCommand("^$", "source list")) + { + CommandObjectSP list_regex_cmd_sp(list_regex_cmd_ap.release()); + m_command_dict[list_regex_cmd_sp->GetCommandName ()] = list_regex_cmd_sp; + } + } + + std::unique_ptr<CommandObjectRegexCommand> + env_regex_cmd_ap(new CommandObjectRegexCommand (*this, + "_regexp-env", + "Implements a shortcut to viewing and setting environment variables.", + "_regexp-env\n_regexp-env FOO=BAR", 2)); + if (env_regex_cmd_ap.get()) + { + if (env_regex_cmd_ap->AddRegexCommand("^$", "settings show target.env-vars") && + env_regex_cmd_ap->AddRegexCommand("^([A-Za-z_][A-Za-z_0-9]*=.*)$", "settings set target.env-vars %1")) + { + CommandObjectSP env_regex_cmd_sp(env_regex_cmd_ap.release()); + m_command_dict[env_regex_cmd_sp->GetCommandName ()] = env_regex_cmd_sp; + } + } + +} + +int +CommandInterpreter::GetCommandNamesMatchingPartialString (const char *cmd_str, bool include_aliases, + StringList &matches) +{ + CommandObject::AddNamesMatchingPartialString (m_command_dict, cmd_str, matches); + + if (include_aliases) + { + CommandObject::AddNamesMatchingPartialString (m_alias_dict, cmd_str, matches); + } + + return matches.GetSize(); +} + +CommandObjectSP +CommandInterpreter::GetCommandSP (const char *cmd_cstr, bool include_aliases, bool exact, StringList *matches) +{ + CommandObject::CommandMap::iterator pos; + CommandObjectSP command_sp; + + std::string cmd(cmd_cstr); + + if (HasCommands()) + { + pos = m_command_dict.find(cmd); + if (pos != m_command_dict.end()) + command_sp = pos->second; + } + + if (include_aliases && HasAliases()) + { + pos = m_alias_dict.find(cmd); + if (pos != m_alias_dict.end()) + command_sp = pos->second; + } + + if (HasUserCommands()) + { + pos = m_user_dict.find(cmd); + if (pos != m_user_dict.end()) + command_sp = pos->second; + } + + if (!exact && !command_sp) + { + // We will only get into here if we didn't find any exact matches. + + CommandObjectSP user_match_sp, alias_match_sp, real_match_sp; + + StringList local_matches; + if (matches == NULL) + matches = &local_matches; + + unsigned int num_cmd_matches = 0; + unsigned int num_alias_matches = 0; + unsigned int num_user_matches = 0; + + // Look through the command dictionaries one by one, and if we get only one match from any of + // them in toto, then return that, otherwise return an empty CommandObjectSP and the list of matches. + + if (HasCommands()) + { + num_cmd_matches = CommandObject::AddNamesMatchingPartialString (m_command_dict, cmd_cstr, *matches); + } + + if (num_cmd_matches == 1) + { + cmd.assign(matches->GetStringAtIndex(0)); + pos = m_command_dict.find(cmd); + if (pos != m_command_dict.end()) + real_match_sp = pos->second; + } + + if (include_aliases && HasAliases()) + { + num_alias_matches = CommandObject::AddNamesMatchingPartialString (m_alias_dict, cmd_cstr, *matches); + + } + + if (num_alias_matches == 1) + { + cmd.assign(matches->GetStringAtIndex (num_cmd_matches)); + pos = m_alias_dict.find(cmd); + if (pos != m_alias_dict.end()) + alias_match_sp = pos->second; + } + + if (HasUserCommands()) + { + num_user_matches = CommandObject::AddNamesMatchingPartialString (m_user_dict, cmd_cstr, *matches); + } + + if (num_user_matches == 1) + { + cmd.assign (matches->GetStringAtIndex (num_cmd_matches + num_alias_matches)); + + pos = m_user_dict.find (cmd); + if (pos != m_user_dict.end()) + user_match_sp = pos->second; + } + + // If we got exactly one match, return that, otherwise return the match list. + + if (num_user_matches + num_cmd_matches + num_alias_matches == 1) + { + if (num_cmd_matches) + return real_match_sp; + else if (num_alias_matches) + return alias_match_sp; + else + return user_match_sp; + } + } + else if (matches && command_sp) + { + matches->AppendString (cmd_cstr); + } + + + return command_sp; +} + +bool +CommandInterpreter::AddCommand (const char *name, const lldb::CommandObjectSP &cmd_sp, bool can_replace) +{ + if (name && name[0]) + { + std::string name_sstr(name); + bool found = (m_command_dict.find (name_sstr) != m_command_dict.end()); + if (found && !can_replace) + return false; + if (found && m_command_dict[name_sstr]->IsRemovable() == false) + return false; + m_command_dict[name_sstr] = cmd_sp; + return true; + } + return false; +} + +bool +CommandInterpreter::AddUserCommand (std::string name, + const lldb::CommandObjectSP &cmd_sp, + bool can_replace) +{ + if (!name.empty()) + { + + const char* name_cstr = name.c_str(); + + // do not allow replacement of internal commands + if (CommandExists(name_cstr)) + { + if (can_replace == false) + return false; + if (m_command_dict[name]->IsRemovable() == false) + return false; + } + + if (UserCommandExists(name_cstr)) + { + if (can_replace == false) + return false; + if (m_user_dict[name]->IsRemovable() == false) + return false; + } + + m_user_dict[name] = cmd_sp; + return true; + } + return false; +} + +CommandObjectSP +CommandInterpreter::GetCommandSPExact (const char *cmd_cstr, bool include_aliases) +{ + Args cmd_words (cmd_cstr); // Break up the command string into words, in case it's a multi-word command. + CommandObjectSP ret_val; // Possibly empty return value. + + if (cmd_cstr == NULL) + return ret_val; + + if (cmd_words.GetArgumentCount() == 1) + return GetCommandSP(cmd_cstr, include_aliases, true, NULL); + else + { + // We have a multi-word command (seemingly), so we need to do more work. + // First, get the cmd_obj_sp for the first word in the command. + CommandObjectSP cmd_obj_sp = GetCommandSP (cmd_words.GetArgumentAtIndex (0), include_aliases, true, NULL); + if (cmd_obj_sp.get() != NULL) + { + // Loop through the rest of the words in the command (everything passed in was supposed to be part of a + // command name), and find the appropriate sub-command SP for each command word.... + size_t end = cmd_words.GetArgumentCount(); + for (size_t j= 1; j < end; ++j) + { + if (cmd_obj_sp->IsMultiwordObject()) + { + cmd_obj_sp = cmd_obj_sp->GetSubcommandSP (cmd_words.GetArgumentAtIndex (j)); + if (cmd_obj_sp.get() == NULL) + // The sub-command name was invalid. Fail and return the empty 'ret_val'. + return ret_val; + } + else + // We have more words in the command name, but we don't have a multiword object. Fail and return + // empty 'ret_val'. + return ret_val; + } + // We successfully looped through all the command words and got valid command objects for them. Assign the + // last object retrieved to 'ret_val'. + ret_val = cmd_obj_sp; + } + } + return ret_val; +} + +CommandObject * +CommandInterpreter::GetCommandObjectExact (const char *cmd_cstr, bool include_aliases) +{ + return GetCommandSPExact (cmd_cstr, include_aliases).get(); +} + +CommandObject * +CommandInterpreter::GetCommandObject (const char *cmd_cstr, StringList *matches) +{ + CommandObject *command_obj = GetCommandSP (cmd_cstr, false, true, matches).get(); + + // If we didn't find an exact match to the command string in the commands, look in + // the aliases. + + if (command_obj) + return command_obj; + + command_obj = GetCommandSP (cmd_cstr, true, true, matches).get(); + + if (command_obj) + return command_obj; + + // If there wasn't an exact match then look for an inexact one in just the commands + command_obj = GetCommandSP(cmd_cstr, false, false, NULL).get(); + + // Finally, if there wasn't an inexact match among the commands, look for an inexact + // match in both the commands and aliases. + + if (command_obj) + { + if (matches) + matches->AppendString(command_obj->GetCommandName()); + return command_obj; + } + + return GetCommandSP(cmd_cstr, true, false, matches).get(); +} + +bool +CommandInterpreter::CommandExists (const char *cmd) +{ + return m_command_dict.find(cmd) != m_command_dict.end(); +} + +bool +CommandInterpreter::ProcessAliasOptionsArgs (lldb::CommandObjectSP &cmd_obj_sp, + const char *options_args, + OptionArgVectorSP &option_arg_vector_sp) +{ + bool success = true; + OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); + + if (!options_args || (strlen (options_args) < 1)) + return true; + + std::string options_string (options_args); + Args args (options_args); + CommandReturnObject result; + // Check to see if the command being aliased can take any command options. + Options *options = cmd_obj_sp->GetOptions (); + if (options) + { + // See if any options were specified as part of the alias; if so, handle them appropriately. + options->NotifyOptionParsingStarting (); + args.Unshift ("dummy_arg"); + args.ParseAliasOptions (*options, result, option_arg_vector, options_string); + args.Shift (); + if (result.Succeeded()) + options->VerifyPartialOptions (result); + if (!result.Succeeded() && result.GetStatus() != lldb::eReturnStatusStarted) + { + result.AppendError ("Unable to create requested alias.\n"); + return false; + } + } + + if (!options_string.empty()) + { + if (cmd_obj_sp->WantsRawCommandString ()) + option_arg_vector->push_back (OptionArgPair ("<argument>", + OptionArgValue (-1, + options_string))); + else + { + const size_t argc = args.GetArgumentCount(); + for (size_t i = 0; i < argc; ++i) + if (strcmp (args.GetArgumentAtIndex (i), "") != 0) + option_arg_vector->push_back + (OptionArgPair ("<argument>", + OptionArgValue (-1, + std::string (args.GetArgumentAtIndex (i))))); + } + } + + return success; +} + +bool +CommandInterpreter::GetAliasFullName (const char *cmd, std::string &full_name) +{ + bool exact_match = (m_alias_dict.find(cmd) != m_alias_dict.end()); + if (exact_match) + { + full_name.assign(cmd); + return exact_match; + } + else + { + StringList matches; + size_t num_alias_matches; + num_alias_matches = CommandObject::AddNamesMatchingPartialString (m_alias_dict, cmd, matches); + if (num_alias_matches == 1) + { + // Make sure this isn't shadowing a command in the regular command space: + StringList regular_matches; + const bool include_aliases = false; + const bool exact = false; + CommandObjectSP cmd_obj_sp(GetCommandSP (cmd, include_aliases, exact, ®ular_matches)); + if (cmd_obj_sp || regular_matches.GetSize() > 0) + return false; + else + { + full_name.assign (matches.GetStringAtIndex(0)); + return true; + } + } + else + return false; + } +} + +bool +CommandInterpreter::AliasExists (const char *cmd) +{ + return m_alias_dict.find(cmd) != m_alias_dict.end(); +} + +bool +CommandInterpreter::UserCommandExists (const char *cmd) +{ + return m_user_dict.find(cmd) != m_user_dict.end(); +} + +void +CommandInterpreter::AddAlias (const char *alias_name, CommandObjectSP& command_obj_sp) +{ + command_obj_sp->SetIsAlias (true); + m_alias_dict[alias_name] = command_obj_sp; +} + +bool +CommandInterpreter::RemoveAlias (const char *alias_name) +{ + CommandObject::CommandMap::iterator pos = m_alias_dict.find(alias_name); + if (pos != m_alias_dict.end()) + { + m_alias_dict.erase(pos); + return true; + } + return false; +} +bool +CommandInterpreter::RemoveUser (const char *alias_name) +{ + CommandObject::CommandMap::iterator pos = m_user_dict.find(alias_name); + if (pos != m_user_dict.end()) + { + m_user_dict.erase(pos); + return true; + } + return false; +} + +void +CommandInterpreter::GetAliasHelp (const char *alias_name, const char *command_name, StreamString &help_string) +{ + help_string.Printf ("'%s", command_name); + OptionArgVectorSP option_arg_vector_sp = GetAliasOptions (alias_name); + + if (option_arg_vector_sp) + { + OptionArgVector *options = option_arg_vector_sp.get(); + for (size_t i = 0; i < options->size(); ++i) + { + OptionArgPair cur_option = (*options)[i]; + std::string opt = cur_option.first; + OptionArgValue value_pair = cur_option.second; + std::string value = value_pair.second; + if (opt.compare("<argument>") == 0) + { + help_string.Printf (" %s", value.c_str()); + } + else + { + help_string.Printf (" %s", opt.c_str()); + if ((value.compare ("<no-argument>") != 0) + && (value.compare ("<need-argument") != 0)) + { + help_string.Printf (" %s", value.c_str()); + } + } + } + } + + help_string.Printf ("'"); +} + +size_t +CommandInterpreter::FindLongestCommandWord (CommandObject::CommandMap &dict) +{ + CommandObject::CommandMap::const_iterator pos; + CommandObject::CommandMap::const_iterator end = dict.end(); + size_t max_len = 0; + + for (pos = dict.begin(); pos != end; ++pos) + { + size_t len = pos->first.size(); + if (max_len < len) + max_len = len; + } + return max_len; +} + +void +CommandInterpreter::GetHelp (CommandReturnObject &result, + uint32_t cmd_types) +{ + CommandObject::CommandMap::const_iterator pos; + size_t max_len = FindLongestCommandWord (m_command_dict); + + if ( (cmd_types & eCommandTypesBuiltin) == eCommandTypesBuiltin ) + { + + result.AppendMessage("The following is a list of built-in, permanent debugger commands:"); + result.AppendMessage(""); + + for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) + { + OutputFormattedHelpText (result.GetOutputStream(), pos->first.c_str(), "--", pos->second->GetHelp(), + max_len); + } + result.AppendMessage(""); + + } + + if (!m_alias_dict.empty() && ( (cmd_types & eCommandTypesAliases) == eCommandTypesAliases )) + { + result.AppendMessage("The following is a list of your current command abbreviations " + "(see 'help command alias' for more info):"); + result.AppendMessage(""); + max_len = FindLongestCommandWord (m_alias_dict); + + for (pos = m_alias_dict.begin(); pos != m_alias_dict.end(); ++pos) + { + StreamString sstr; + StreamString translation_and_help; + std::string entry_name = pos->first; + std::string second_entry = pos->second.get()->GetCommandName(); + GetAliasHelp (pos->first.c_str(), pos->second->GetCommandName(), sstr); + + translation_and_help.Printf ("(%s) %s", sstr.GetData(), pos->second->GetHelp()); + OutputFormattedHelpText (result.GetOutputStream(), pos->first.c_str(), "--", + translation_and_help.GetData(), max_len); + } + result.AppendMessage(""); + } + + if (!m_user_dict.empty() && ( (cmd_types & eCommandTypesUserDef) == eCommandTypesUserDef )) + { + result.AppendMessage ("The following is a list of your current user-defined commands:"); + result.AppendMessage(""); + max_len = FindLongestCommandWord (m_user_dict); + for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) + { + OutputFormattedHelpText (result.GetOutputStream(), pos->first.c_str(), "--", pos->second->GetHelp(), + max_len); + } + result.AppendMessage(""); + } + + result.AppendMessage("For more information on any particular command, try 'help <command-name>'."); +} + +CommandObject * +CommandInterpreter::GetCommandObjectForCommand (std::string &command_string) +{ + // This function finds the final, lowest-level, alias-resolved command object whose 'Execute' function will + // eventually be invoked by the given command line. + + CommandObject *cmd_obj = NULL; + std::string white_space (" \t\v"); + size_t start = command_string.find_first_not_of (white_space); + size_t end = 0; + bool done = false; + while (!done) + { + if (start != std::string::npos) + { + // Get the next word from command_string. + end = command_string.find_first_of (white_space, start); + if (end == std::string::npos) + end = command_string.size(); + std::string cmd_word = command_string.substr (start, end - start); + + if (cmd_obj == NULL) + // Since cmd_obj is NULL we are on our first time through this loop. Check to see if cmd_word is a valid + // command or alias. + cmd_obj = GetCommandObject (cmd_word.c_str()); + else if (cmd_obj->IsMultiwordObject ()) + { + // Our current object is a multi-word object; see if the cmd_word is a valid sub-command for our object. + CommandObject *sub_cmd_obj = cmd_obj->GetSubcommandObject (cmd_word.c_str()); + if (sub_cmd_obj) + cmd_obj = sub_cmd_obj; + else // cmd_word was not a valid sub-command word, so we are donee + done = true; + } + else + // We have a cmd_obj and it is not a multi-word object, so we are done. + done = true; + + // If we didn't find a valid command object, or our command object is not a multi-word object, or + // we are at the end of the command_string, then we are done. Otherwise, find the start of the + // next word. + + if (!cmd_obj || !cmd_obj->IsMultiwordObject() || end >= command_string.size()) + done = true; + else + start = command_string.find_first_not_of (white_space, end); + } + else + // Unable to find any more words. + done = true; + } + + if (end == command_string.size()) + command_string.clear(); + else + command_string = command_string.substr(end); + + return cmd_obj; +} + +static const char *k_white_space = " \t\v"; +static const char *k_valid_command_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; +static void +StripLeadingSpaces (std::string &s) +{ + if (!s.empty()) + { + size_t pos = s.find_first_not_of (k_white_space); + if (pos == std::string::npos) + s.clear(); + else if (pos == 0) + return; + s.erase (0, pos); + } +} + +static size_t +FindArgumentTerminator (const std::string &s) +{ + const size_t s_len = s.size(); + size_t offset = 0; + while (offset < s_len) + { + size_t pos = s.find ("--", offset); + if (pos == std::string::npos) + break; + if (pos > 0) + { + if (isspace(s[pos-1])) + { + // Check if the string ends "\s--" (where \s is a space character) + // or if we have "\s--\s". + if ((pos + 2 >= s_len) || isspace(s[pos+2])) + { + return pos; + } + } + } + offset = pos + 2; + } + return std::string::npos; +} + +static bool +ExtractCommand (std::string &command_string, std::string &command, std::string &suffix, char "e_char) +{ + command.clear(); + suffix.clear(); + StripLeadingSpaces (command_string); + + bool result = false; + quote_char = '\0'; + + if (!command_string.empty()) + { + const char first_char = command_string[0]; + if (first_char == '\'' || first_char == '"') + { + quote_char = first_char; + const size_t end_quote_pos = command_string.find (quote_char, 1); + if (end_quote_pos == std::string::npos) + { + command.swap (command_string); + command_string.erase (); + } + else + { + command.assign (command_string, 1, end_quote_pos - 1); + if (end_quote_pos + 1 < command_string.size()) + command_string.erase (0, command_string.find_first_not_of (k_white_space, end_quote_pos + 1)); + else + command_string.erase (); + } + } + else + { + const size_t first_space_pos = command_string.find_first_of (k_white_space); + if (first_space_pos == std::string::npos) + { + command.swap (command_string); + command_string.erase(); + } + else + { + command.assign (command_string, 0, first_space_pos); + command_string.erase(0, command_string.find_first_not_of (k_white_space, first_space_pos)); + } + } + result = true; + } + + + if (!command.empty()) + { + // actual commands can't start with '-' or '_' + if (command[0] != '-' && command[0] != '_') + { + size_t pos = command.find_first_not_of(k_valid_command_chars); + if (pos > 0 && pos != std::string::npos) + { + suffix.assign (command.begin() + pos, command.end()); + command.erase (pos); + } + } + } + + return result; +} + +CommandObject * +CommandInterpreter::BuildAliasResult (const char *alias_name, + std::string &raw_input_string, + std::string &alias_result, + CommandReturnObject &result) +{ + CommandObject *alias_cmd_obj = NULL; + Args cmd_args (raw_input_string.c_str()); + alias_cmd_obj = GetCommandObject (alias_name); + StreamString result_str; + + if (alias_cmd_obj) + { + std::string alias_name_str = alias_name; + if ((cmd_args.GetArgumentCount() == 0) + || (alias_name_str.compare (cmd_args.GetArgumentAtIndex(0)) != 0)) + cmd_args.Unshift (alias_name); + + result_str.Printf ("%s", alias_cmd_obj->GetCommandName ()); + OptionArgVectorSP option_arg_vector_sp = GetAliasOptions (alias_name); + + if (option_arg_vector_sp.get()) + { + OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); + + for (size_t i = 0; i < option_arg_vector->size(); ++i) + { + OptionArgPair option_pair = (*option_arg_vector)[i]; + OptionArgValue value_pair = option_pair.second; + int value_type = value_pair.first; + std::string option = option_pair.first; + std::string value = value_pair.second; + if (option.compare ("<argument>") == 0) + result_str.Printf (" %s", value.c_str()); + else + { + result_str.Printf (" %s", option.c_str()); + if (value_type != optional_argument) + result_str.Printf (" "); + if (value.compare ("<no_argument>") != 0) + { + int index = GetOptionArgumentPosition (value.c_str()); + if (index == 0) + result_str.Printf ("%s", value.c_str()); + else if (index >= cmd_args.GetArgumentCount()) + { + + result.AppendErrorWithFormat + ("Not enough arguments provided; you need at least %d arguments to use this alias.\n", + index); + result.SetStatus (eReturnStatusFailed); + return alias_cmd_obj; + } + else + { + size_t strpos = raw_input_string.find (cmd_args.GetArgumentAtIndex (index)); + if (strpos != std::string::npos) + raw_input_string = raw_input_string.erase (strpos, + strlen (cmd_args.GetArgumentAtIndex (index))); + result_str.Printf ("%s", cmd_args.GetArgumentAtIndex (index)); + } + } + } + } + } + + alias_result = result_str.GetData(); + } + return alias_cmd_obj; +} + +Error +CommandInterpreter::PreprocessCommand (std::string &command) +{ + // The command preprocessor needs to do things to the command + // line before any parsing of arguments or anything else is done. + // The only current stuff that gets proprocessed is anyting enclosed + // in backtick ('`') characters is evaluated as an expression and + // the result of the expression must be a scalar that can be substituted + // into the command. An example would be: + // (lldb) memory read `$rsp + 20` + Error error; // Error for any expressions that might not evaluate + size_t start_backtick; + size_t pos = 0; + while ((start_backtick = command.find ('`', pos)) != std::string::npos) + { + if (start_backtick > 0 && command[start_backtick-1] == '\\') + { + // The backtick was preceeded by a '\' character, remove the slash + // and don't treat the backtick as the start of an expression + command.erase(start_backtick-1, 1); + // No need to add one to start_backtick since we just deleted a char + pos = start_backtick; + } + else + { + const size_t expr_content_start = start_backtick + 1; + const size_t end_backtick = command.find ('`', expr_content_start); + if (end_backtick == std::string::npos) + return error; + else if (end_backtick == expr_content_start) + { + // Empty expression (two backticks in a row) + command.erase (start_backtick, 2); + } + else + { + std::string expr_str (command, expr_content_start, end_backtick - expr_content_start); + + ExecutionContext exe_ctx(GetExecutionContext()); + Target *target = exe_ctx.GetTargetPtr(); + // Get a dummy target to allow for calculator mode while processing backticks. + // This also helps break the infinite loop caused when target is null. + if (!target) + target = Host::GetDummyTarget(GetDebugger()).get(); + if (target) + { + ValueObjectSP expr_result_valobj_sp; + + EvaluateExpressionOptions options; + options.SetCoerceToId(false) + .SetUnwindOnError(true) + .SetIgnoreBreakpoints(true) + .SetKeepInMemory(false) + .SetRunOthers(true) + .SetTimeoutUsec(0); + + ExecutionResults expr_result = target->EvaluateExpression (expr_str.c_str(), + exe_ctx.GetFramePtr(), + expr_result_valobj_sp, + options); + + if (expr_result == eExecutionCompleted) + { + Scalar scalar; + if (expr_result_valobj_sp->ResolveValue (scalar)) + { + command.erase (start_backtick, end_backtick - start_backtick + 1); + StreamString value_strm; + const bool show_type = false; + scalar.GetValue (&value_strm, show_type); + size_t value_string_size = value_strm.GetSize(); + if (value_string_size) + { + command.insert (start_backtick, value_strm.GetData(), value_string_size); + pos = start_backtick + value_string_size; + continue; + } + else + { + error.SetErrorStringWithFormat("expression value didn't result in a scalar value for the expression '%s'", expr_str.c_str()); + } + } + else + { + error.SetErrorStringWithFormat("expression value didn't result in a scalar value for the expression '%s'", expr_str.c_str()); + } + } + else + { + if (expr_result_valobj_sp) + error = expr_result_valobj_sp->GetError(); + if (error.Success()) + { + + switch (expr_result) + { + case eExecutionSetupError: + error.SetErrorStringWithFormat("expression setup error for the expression '%s'", expr_str.c_str()); + break; + case eExecutionCompleted: + break; + case eExecutionDiscarded: + error.SetErrorStringWithFormat("expression discarded for the expression '%s'", expr_str.c_str()); + break; + case eExecutionInterrupted: + error.SetErrorStringWithFormat("expression interrupted for the expression '%s'", expr_str.c_str()); + break; + case eExecutionHitBreakpoint: + error.SetErrorStringWithFormat("expression hit breakpoint for the expression '%s'", expr_str.c_str()); + break; + case eExecutionTimedOut: + error.SetErrorStringWithFormat("expression timed out for the expression '%s'", expr_str.c_str()); + break; + } + } + } + } + } + if (error.Fail()) + break; + } + } + return error; +} + + +bool +CommandInterpreter::HandleCommand (const char *command_line, + LazyBool lazy_add_to_history, + CommandReturnObject &result, + ExecutionContext *override_context, + bool repeat_on_empty_command, + bool no_context_switching) + +{ + + bool done = false; + CommandObject *cmd_obj = NULL; + bool wants_raw_input = false; + std::string command_string (command_line); + std::string original_command_string (command_line); + + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMANDS)); + Host::SetCrashDescriptionWithFormat ("HandleCommand(command = \"%s\")", command_line); + + // Make a scoped cleanup object that will clear the crash description string + // on exit of this function. + lldb_utility::CleanUp <const char *> crash_description_cleanup(NULL, Host::SetCrashDescription); + + if (log) + log->Printf ("Processing command: %s", command_line); + + Timer scoped_timer (__PRETTY_FUNCTION__, "Handling command: %s.", command_line); + + if (!no_context_switching) + UpdateExecutionContext (override_context); + + bool add_to_history; + if (lazy_add_to_history == eLazyBoolCalculate) + add_to_history = (m_command_source_depth == 0); + else + add_to_history = (lazy_add_to_history == eLazyBoolYes); + + bool empty_command = false; + bool comment_command = false; + if (command_string.empty()) + empty_command = true; + else + { + const char *k_space_characters = "\t\n\v\f\r "; + + size_t non_space = command_string.find_first_not_of (k_space_characters); + // Check for empty line or comment line (lines whose first + // non-space character is the comment character for this interpreter) + if (non_space == std::string::npos) + empty_command = true; + else if (command_string[non_space] == m_comment_char) + comment_command = true; + else if (command_string[non_space] == CommandHistory::g_repeat_char) + { + const char *history_string = m_command_history.FindString(command_string.c_str() + non_space); + if (history_string == NULL) + { + result.AppendErrorWithFormat ("Could not find entry: %s in history", command_string.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + add_to_history = false; + command_string = history_string; + original_command_string = history_string; + } + } + + if (empty_command) + { + if (repeat_on_empty_command) + { + if (m_command_history.IsEmpty()) + { + result.AppendError ("empty command"); + result.SetStatus(eReturnStatusFailed); + return false; + } + else + { + command_line = m_repeat_command.c_str(); + command_string = command_line; + original_command_string = command_line; + if (m_repeat_command.empty()) + { + result.AppendErrorWithFormat("No auto repeat.\n"); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + add_to_history = false; + } + else + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + return true; + } + } + else if (comment_command) + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + return true; + } + + + Error error (PreprocessCommand (command_string)); + + if (error.Fail()) + { + result.AppendError (error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; + } + // Phase 1. + + // Before we do ANY kind of argument processing, etc. we need to figure out what the real/final command object + // is for the specified command, and whether or not it wants raw input. This gets complicated by the fact that + // the user could have specified an alias, and in translating the alias there may also be command options and/or + // even data (including raw text strings) that need to be found and inserted into the command line as part of + // the translation. So this first step is plain look-up & replacement, resulting in three things: 1). the command + // object whose Execute method will actually be called; 2). a revised command string, with all substitutions & + // replacements taken care of; 3). whether or not the Execute function wants raw input or not. + + StreamString revised_command_line; + size_t actual_cmd_name_len = 0; + std::string next_word; + StringList matches; + while (!done) + { + char quote_char = '\0'; + std::string suffix; + ExtractCommand (command_string, next_word, suffix, quote_char); + if (cmd_obj == NULL) + { + std::string full_name; + if (GetAliasFullName(next_word.c_str(), full_name)) + { + std::string alias_result; + cmd_obj = BuildAliasResult (full_name.c_str(), command_string, alias_result, result); + revised_command_line.Printf ("%s", alias_result.c_str()); + if (cmd_obj) + { + wants_raw_input = cmd_obj->WantsRawCommandString (); + actual_cmd_name_len = strlen (cmd_obj->GetCommandName()); + } + } + else + { + cmd_obj = GetCommandObject (next_word.c_str(), &matches); + if (cmd_obj) + { + actual_cmd_name_len += next_word.length(); + revised_command_line.Printf ("%s", next_word.c_str()); + wants_raw_input = cmd_obj->WantsRawCommandString (); + } + else + { + revised_command_line.Printf ("%s", next_word.c_str()); + } + } + } + else + { + if (cmd_obj->IsMultiwordObject ()) + { + CommandObject *sub_cmd_obj = cmd_obj->GetSubcommandObject (next_word.c_str()); + if (sub_cmd_obj) + { + actual_cmd_name_len += next_word.length() + 1; + revised_command_line.Printf (" %s", next_word.c_str()); + cmd_obj = sub_cmd_obj; + wants_raw_input = cmd_obj->WantsRawCommandString (); + } + else + { + if (quote_char) + revised_command_line.Printf (" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char); + else + revised_command_line.Printf (" %s%s", next_word.c_str(), suffix.c_str()); + done = true; + } + } + else + { + if (quote_char) + revised_command_line.Printf (" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char); + else + revised_command_line.Printf (" %s%s", next_word.c_str(), suffix.c_str()); + done = true; + } + } + + if (cmd_obj == NULL) + { + const size_t num_matches = matches.GetSize(); + if (matches.GetSize() > 1) { + StreamString error_msg; + error_msg.Printf ("Ambiguous command '%s'. Possible matches:\n", next_word.c_str()); + + for (uint32_t i = 0; i < num_matches; ++i) { + error_msg.Printf ("\t%s\n", matches.GetStringAtIndex(i)); + } + result.AppendRawError (error_msg.GetString().c_str()); + } else { + // We didn't have only one match, otherwise we wouldn't get here. + assert(num_matches == 0); + result.AppendErrorWithFormat ("'%s' is not a valid command.\n", next_word.c_str()); + } + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (cmd_obj->IsMultiwordObject ()) + { + if (!suffix.empty()) + { + + result.AppendErrorWithFormat ("command '%s' did not recognize '%s%s%s' as valid (subcommand might be invalid).\n", + cmd_obj->GetCommandName(), + next_word.empty() ? "" : next_word.c_str(), + next_word.empty() ? " -- " : " ", + suffix.c_str()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + // If we found a normal command, we are done + done = true; + if (!suffix.empty()) + { + switch (suffix[0]) + { + case '/': + // GDB format suffixes + { + Options *command_options = cmd_obj->GetOptions(); + if (command_options && command_options->SupportsLongOption("gdb-format")) + { + std::string gdb_format_option ("--gdb-format="); + gdb_format_option += (suffix.c_str() + 1); + + bool inserted = false; + std::string &cmd = revised_command_line.GetString(); + size_t arg_terminator_idx = FindArgumentTerminator (cmd); + if (arg_terminator_idx != std::string::npos) + { + // Insert the gdb format option before the "--" that terminates options + gdb_format_option.append(1,' '); + cmd.insert(arg_terminator_idx, gdb_format_option); + inserted = true; + } + + if (!inserted) + revised_command_line.Printf (" %s", gdb_format_option.c_str()); + + if (wants_raw_input && FindArgumentTerminator(cmd) == std::string::npos) + revised_command_line.PutCString (" --"); + } + else + { + result.AppendErrorWithFormat ("the '%s' command doesn't support the --gdb-format option\n", + cmd_obj->GetCommandName()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + break; + + default: + result.AppendErrorWithFormat ("unknown command shorthand suffix: '%s'\n", + suffix.c_str()); + result.SetStatus (eReturnStatusFailed); + return false; + + } + } + } + if (command_string.length() == 0) + done = true; + + } + + if (!command_string.empty()) + revised_command_line.Printf (" %s", command_string.c_str()); + + // End of Phase 1. + // At this point cmd_obj should contain the CommandObject whose Execute method will be called, if the command + // specified was valid; revised_command_line contains the complete command line (including command name(s)), + // fully translated with all substitutions & translations taken care of (still in raw text format); and + // wants_raw_input specifies whether the Execute method expects raw input or not. + + + if (log) + { + log->Printf ("HandleCommand, cmd_obj : '%s'", cmd_obj ? cmd_obj->GetCommandName() : "<not found>"); + log->Printf ("HandleCommand, revised_command_line: '%s'", revised_command_line.GetData()); + log->Printf ("HandleCommand, wants_raw_input:'%s'", wants_raw_input ? "True" : "False"); + } + + // Phase 2. + // Take care of things like setting up the history command & calling the appropriate Execute method on the + // CommandObject, with the appropriate arguments. + + if (cmd_obj != NULL) + { + if (add_to_history) + { + Args command_args (revised_command_line.GetData()); + const char *repeat_command = cmd_obj->GetRepeatCommand(command_args, 0); + if (repeat_command != NULL) + m_repeat_command.assign(repeat_command); + else + m_repeat_command.assign(original_command_string.c_str()); + + m_command_history.AppendString (original_command_string); + } + + command_string = revised_command_line.GetData(); + std::string command_name (cmd_obj->GetCommandName()); + std::string remainder; + if (actual_cmd_name_len < command_string.length()) + remainder = command_string.substr (actual_cmd_name_len); // Note: 'actual_cmd_name_len' may be considerably shorter + // than cmd_obj->GetCommandName(), because name completion + // allows users to enter short versions of the names, + // e.g. 'br s' for 'breakpoint set'. + + // Remove any initial spaces + std::string white_space (" \t\v"); + size_t pos = remainder.find_first_not_of (white_space); + if (pos != 0 && pos != std::string::npos) + remainder.erase(0, pos); + + if (log) + log->Printf ("HandleCommand, command line after removing command name(s): '%s'", remainder.c_str()); + + cmd_obj->Execute (remainder.c_str(), result); + } + else + { + // We didn't find the first command object, so complete the first argument. + Args command_args (revised_command_line.GetData()); + StringList matches; + int num_matches; + int cursor_index = 0; + int cursor_char_position = strlen (command_args.GetArgumentAtIndex(0)); + bool word_complete; + num_matches = HandleCompletionMatches (command_args, + cursor_index, + cursor_char_position, + 0, + -1, + word_complete, + matches); + + if (num_matches > 0) + { + std::string error_msg; + error_msg.assign ("ambiguous command '"); + error_msg.append(command_args.GetArgumentAtIndex(0)); + error_msg.append ("'."); + + error_msg.append (" Possible completions:"); + for (int i = 0; i < num_matches; i++) + { + error_msg.append ("\n\t"); + error_msg.append (matches.GetStringAtIndex (i)); + } + error_msg.append ("\n"); + result.AppendRawError (error_msg.c_str()); + } + else + result.AppendErrorWithFormat ("Unrecognized command '%s'.\n", command_args.GetArgumentAtIndex (0)); + + result.SetStatus (eReturnStatusFailed); + } + + if (log) + log->Printf ("HandleCommand, command %s", (result.Succeeded() ? "succeeded" : "did not succeed")); + + return result.Succeeded(); +} + +int +CommandInterpreter::HandleCompletionMatches (Args &parsed_line, + int &cursor_index, + int &cursor_char_position, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches) +{ + int num_command_matches = 0; + bool look_for_subcommand = false; + + // For any of the command completions a unique match will be a complete word. + word_complete = true; + + if (cursor_index == -1) + { + // We got nothing on the command line, so return the list of commands + bool include_aliases = true; + num_command_matches = GetCommandNamesMatchingPartialString ("", include_aliases, matches); + } + else if (cursor_index == 0) + { + // The cursor is in the first argument, so just do a lookup in the dictionary. + CommandObject *cmd_obj = GetCommandObject (parsed_line.GetArgumentAtIndex(0), &matches); + num_command_matches = matches.GetSize(); + + if (num_command_matches == 1 + && cmd_obj && cmd_obj->IsMultiwordObject() + && matches.GetStringAtIndex(0) != NULL + && strcmp (parsed_line.GetArgumentAtIndex(0), matches.GetStringAtIndex(0)) == 0) + { + look_for_subcommand = true; + num_command_matches = 0; + matches.DeleteStringAtIndex(0); + parsed_line.AppendArgument (""); + cursor_index++; + cursor_char_position = 0; + } + } + + if (cursor_index > 0 || look_for_subcommand) + { + // We are completing further on into a commands arguments, so find the command and tell it + // to complete the command. + // First see if there is a matching initial command: + CommandObject *command_object = GetCommandObject (parsed_line.GetArgumentAtIndex(0)); + if (command_object == NULL) + { + return 0; + } + else + { + parsed_line.Shift(); + cursor_index--; + num_command_matches = command_object->HandleCompletion (parsed_line, + cursor_index, + cursor_char_position, + match_start_point, + max_return_elements, + word_complete, + matches); + } + } + + return num_command_matches; + +} + +int +CommandInterpreter::HandleCompletion (const char *current_line, + const char *cursor, + const char *last_char, + int match_start_point, + int max_return_elements, + StringList &matches) +{ + // We parse the argument up to the cursor, so the last argument in parsed_line is + // the one containing the cursor, and the cursor is after the last character. + + Args parsed_line(current_line, last_char - current_line); + Args partial_parsed_line(current_line, cursor - current_line); + + // Don't complete comments, and if the line we are completing is just the history repeat character, + // substitute the appropriate history line. + const char *first_arg = parsed_line.GetArgumentAtIndex(0); + if (first_arg) + { + if (first_arg[0] == m_comment_char) + return 0; + else if (first_arg[0] == CommandHistory::g_repeat_char) + { + const char *history_string = m_command_history.FindString (first_arg); + if (history_string != NULL) + { + matches.Clear(); + matches.InsertStringAtIndex(0, history_string); + return -2; + } + else + return 0; + + } + } + + + int num_args = partial_parsed_line.GetArgumentCount(); + int cursor_index = partial_parsed_line.GetArgumentCount() - 1; + int cursor_char_position; + + if (cursor_index == -1) + cursor_char_position = 0; + else + cursor_char_position = strlen (partial_parsed_line.GetArgumentAtIndex(cursor_index)); + + if (cursor > current_line && cursor[-1] == ' ') + { + // We are just after a space. If we are in an argument, then we will continue + // parsing, but if we are between arguments, then we have to complete whatever the next + // element would be. + // We can distinguish the two cases because if we are in an argument (e.g. because the space is + // protected by a quote) then the space will also be in the parsed argument... + + const char *current_elem = partial_parsed_line.GetArgumentAtIndex(cursor_index); + if (cursor_char_position == 0 || current_elem[cursor_char_position - 1] != ' ') + { + parsed_line.InsertArgumentAtIndex(cursor_index + 1, "", '"'); + cursor_index++; + cursor_char_position = 0; + } + } + + int num_command_matches; + + matches.Clear(); + + // Only max_return_elements == -1 is supported at present: + assert (max_return_elements == -1); + bool word_complete; + num_command_matches = HandleCompletionMatches (parsed_line, + cursor_index, + cursor_char_position, + match_start_point, + max_return_elements, + word_complete, + matches); + + if (num_command_matches <= 0) + return num_command_matches; + + if (num_args == 0) + { + // If we got an empty string, insert nothing. + matches.InsertStringAtIndex(0, ""); + } + else + { + // Now figure out if there is a common substring, and if so put that in element 0, otherwise + // put an empty string in element 0. + std::string command_partial_str; + if (cursor_index >= 0) + command_partial_str.assign(parsed_line.GetArgumentAtIndex(cursor_index), + parsed_line.GetArgumentAtIndex(cursor_index) + cursor_char_position); + + std::string common_prefix; + matches.LongestCommonPrefix (common_prefix); + const size_t partial_name_len = command_partial_str.size(); + + // If we matched a unique single command, add a space... + // Only do this if the completer told us this was a complete word, however... + if (num_command_matches == 1 && word_complete) + { + char quote_char = parsed_line.GetArgumentQuoteCharAtIndex(cursor_index); + if (quote_char != '\0') + common_prefix.push_back(quote_char); + + common_prefix.push_back(' '); + } + common_prefix.erase (0, partial_name_len); + matches.InsertStringAtIndex(0, common_prefix.c_str()); + } + return num_command_matches; +} + + +CommandInterpreter::~CommandInterpreter () +{ +} + +const char * +CommandInterpreter::GetPrompt () +{ + return m_debugger.GetPrompt(); +} + +void +CommandInterpreter::SetPrompt (const char *new_prompt) +{ + m_debugger.SetPrompt (new_prompt); +} + +size_t +CommandInterpreter::GetConfirmationInputReaderCallback +( + void *baton, + InputReader &reader, + lldb::InputReaderAction action, + const char *bytes, + size_t bytes_len +) +{ + File &out_file = reader.GetDebugger().GetOutputFile(); + bool *response_ptr = (bool *) baton; + + switch (action) + { + case eInputReaderActivate: + if (out_file.IsValid()) + { + if (reader.GetPrompt()) + { + out_file.Printf ("%s", reader.GetPrompt()); + out_file.Flush (); + } + } + break; + + case eInputReaderDeactivate: + break; + + case eInputReaderReactivate: + if (out_file.IsValid() && reader.GetPrompt()) + { + out_file.Printf ("%s", reader.GetPrompt()); + out_file.Flush (); + } + break; + + case eInputReaderAsynchronousOutputWritten: + break; + + case eInputReaderGotToken: + if (bytes_len == 0) + { + reader.SetIsDone(true); + } + else if (bytes[0] == 'y' || bytes[0] == 'Y') + { + *response_ptr = true; + reader.SetIsDone(true); + } + else if (bytes[0] == 'n' || bytes[0] == 'N') + { + *response_ptr = false; + reader.SetIsDone(true); + } + else + { + if (out_file.IsValid() && !reader.IsDone() && reader.GetPrompt()) + { + out_file.Printf ("Please answer \"y\" or \"n\".\n%s", reader.GetPrompt()); + out_file.Flush (); + } + } + break; + + case eInputReaderInterrupt: + case eInputReaderEndOfFile: + *response_ptr = false; // Assume ^C or ^D means cancel the proposed action + reader.SetIsDone (true); + break; + + case eInputReaderDone: + break; + } + + return bytes_len; + +} + +bool +CommandInterpreter::Confirm (const char *message, bool default_answer) +{ + // Check AutoConfirm first: + if (m_debugger.GetAutoConfirm()) + return default_answer; + + InputReaderSP reader_sp (new InputReader(GetDebugger())); + bool response = default_answer; + if (reader_sp) + { + std::string prompt(message); + prompt.append(": ["); + if (default_answer) + prompt.append ("Y/n] "); + else + prompt.append ("y/N] "); + + Error err (reader_sp->Initialize (CommandInterpreter::GetConfirmationInputReaderCallback, + &response, // baton + eInputReaderGranularityLine, // token size, to pass to callback function + NULL, // end token + prompt.c_str(), // prompt + true)); // echo input + if (err.Success()) + { + GetDebugger().PushInputReader (reader_sp); + } + reader_sp->WaitOnReaderIsDone(); + } + return response; +} + +OptionArgVectorSP +CommandInterpreter::GetAliasOptions (const char *alias_name) +{ + OptionArgMap::iterator pos; + OptionArgVectorSP ret_val; + + std::string alias (alias_name); + + if (HasAliasOptions()) + { + pos = m_alias_options.find (alias); + if (pos != m_alias_options.end()) + ret_val = pos->second; + } + + return ret_val; +} + +void +CommandInterpreter::RemoveAliasOptions (const char *alias_name) +{ + OptionArgMap::iterator pos = m_alias_options.find(alias_name); + if (pos != m_alias_options.end()) + { + m_alias_options.erase (pos); + } +} + +void +CommandInterpreter::AddOrReplaceAliasOptions (const char *alias_name, OptionArgVectorSP &option_arg_vector_sp) +{ + m_alias_options[alias_name] = option_arg_vector_sp; +} + +bool +CommandInterpreter::HasCommands () +{ + return (!m_command_dict.empty()); +} + +bool +CommandInterpreter::HasAliases () +{ + return (!m_alias_dict.empty()); +} + +bool +CommandInterpreter::HasUserCommands () +{ + return (!m_user_dict.empty()); +} + +bool +CommandInterpreter::HasAliasOptions () +{ + return (!m_alias_options.empty()); +} + +void +CommandInterpreter::BuildAliasCommandArgs (CommandObject *alias_cmd_obj, + const char *alias_name, + Args &cmd_args, + std::string &raw_input_string, + CommandReturnObject &result) +{ + OptionArgVectorSP option_arg_vector_sp = GetAliasOptions (alias_name); + + bool wants_raw_input = alias_cmd_obj->WantsRawCommandString(); + + // Make sure that the alias name is the 0th element in cmd_args + std::string alias_name_str = alias_name; + if (alias_name_str.compare (cmd_args.GetArgumentAtIndex(0)) != 0) + cmd_args.Unshift (alias_name); + + Args new_args (alias_cmd_obj->GetCommandName()); + if (new_args.GetArgumentCount() == 2) + new_args.Shift(); + + if (option_arg_vector_sp.get()) + { + if (wants_raw_input) + { + // We have a command that both has command options and takes raw input. Make *sure* it has a + // " -- " in the right place in the raw_input_string. + size_t pos = raw_input_string.find(" -- "); + if (pos == std::string::npos) + { + // None found; assume it goes at the beginning of the raw input string + raw_input_string.insert (0, " -- "); + } + } + + OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); + const size_t old_size = cmd_args.GetArgumentCount(); + std::vector<bool> used (old_size + 1, false); + + used[0] = true; + + for (size_t i = 0; i < option_arg_vector->size(); ++i) + { + OptionArgPair option_pair = (*option_arg_vector)[i]; + OptionArgValue value_pair = option_pair.second; + int value_type = value_pair.first; + std::string option = option_pair.first; + std::string value = value_pair.second; + if (option.compare ("<argument>") == 0) + { + if (!wants_raw_input + || (value.compare("--") != 0)) // Since we inserted this above, make sure we don't insert it twice + new_args.AppendArgument (value.c_str()); + } + else + { + if (value_type != optional_argument) + new_args.AppendArgument (option.c_str()); + if (value.compare ("<no-argument>") != 0) + { + int index = GetOptionArgumentPosition (value.c_str()); + if (index == 0) + { + // value was NOT a positional argument; must be a real value + if (value_type != optional_argument) + new_args.AppendArgument (value.c_str()); + else + { + char buffer[255]; + ::snprintf (buffer, sizeof (buffer), "%s%s", option.c_str(), value.c_str()); + new_args.AppendArgument (buffer); + } + + } + else if (index >= cmd_args.GetArgumentCount()) + { + result.AppendErrorWithFormat + ("Not enough arguments provided; you need at least %d arguments to use this alias.\n", + index); + result.SetStatus (eReturnStatusFailed); + return; + } + else + { + // Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string + size_t strpos = raw_input_string.find (cmd_args.GetArgumentAtIndex (index)); + if (strpos != std::string::npos) + { + raw_input_string = raw_input_string.erase (strpos, strlen (cmd_args.GetArgumentAtIndex (index))); + } + + if (value_type != optional_argument) + new_args.AppendArgument (cmd_args.GetArgumentAtIndex (index)); + else + { + char buffer[255]; + ::snprintf (buffer, sizeof(buffer), "%s%s", option.c_str(), + cmd_args.GetArgumentAtIndex (index)); + new_args.AppendArgument (buffer); + } + used[index] = true; + } + } + } + } + + for (size_t j = 0; j < cmd_args.GetArgumentCount(); ++j) + { + if (!used[j] && !wants_raw_input) + new_args.AppendArgument (cmd_args.GetArgumentAtIndex (j)); + } + + cmd_args.Clear(); + cmd_args.SetArguments (new_args.GetArgumentCount(), (const char **) new_args.GetArgumentVector()); + } + else + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + // This alias was not created with any options; nothing further needs to be done, unless it is a command that + // wants raw input, in which case we need to clear the rest of the data from cmd_args, since its in the raw + // input string. + if (wants_raw_input) + { + cmd_args.Clear(); + cmd_args.SetArguments (new_args.GetArgumentCount(), (const char **) new_args.GetArgumentVector()); + } + return; + } + + result.SetStatus (eReturnStatusSuccessFinishNoResult); + return; +} + + +int +CommandInterpreter::GetOptionArgumentPosition (const char *in_string) +{ + int position = 0; // Any string that isn't an argument position, i.e. '%' followed by an integer, gets a position + // of zero. + + char *cptr = (char *) in_string; + + // Does it start with '%' + if (cptr[0] == '%') + { + ++cptr; + + // Is the rest of it entirely digits? + if (isdigit (cptr[0])) + { + const char *start = cptr; + while (isdigit (cptr[0])) + ++cptr; + + // We've gotten to the end of the digits; are we at the end of the string? + if (cptr[0] == '\0') + position = atoi (start); + } + } + + return position; +} + +void +CommandInterpreter::SourceInitFile (bool in_cwd, CommandReturnObject &result) +{ + FileSpec init_file; + if (in_cwd) + { + // In the current working directory we don't load any program specific + // .lldbinit files, we only look for a "./.lldbinit" file. + if (m_skip_lldbinit_files) + return; + + init_file.SetFile ("./.lldbinit", true); + } + else + { + // If we aren't looking in the current working directory we are looking + // in the home directory. We will first see if there is an application + // specific ".lldbinit" file whose name is "~/.lldbinit" followed by a + // "-" and the name of the program. If this file doesn't exist, we fall + // back to just the "~/.lldbinit" file. We also obey any requests to not + // load the init files. + const char *init_file_path = "~/.lldbinit"; + + if (m_skip_app_init_files == false) + { + FileSpec program_file_spec (Host::GetProgramFileSpec()); + const char *program_name = program_file_spec.GetFilename().AsCString(); + + if (program_name) + { + char program_init_file_name[PATH_MAX]; + ::snprintf (program_init_file_name, sizeof(program_init_file_name), "%s-%s", init_file_path, program_name); + init_file.SetFile (program_init_file_name, true); + if (!init_file.Exists()) + init_file.Clear(); + } + } + + if (!init_file && !m_skip_lldbinit_files) + init_file.SetFile (init_file_path, true); + } + + // If the file exists, tell HandleCommand to 'source' it; this will do the actual broadcasting + // of the commands back to any appropriate listener (see CommandObjectSource::Execute for more details). + + if (init_file.Exists()) + { + ExecutionContext *exe_ctx = NULL; // We don't have any context yet. + bool stop_on_continue = true; + bool stop_on_error = false; + bool echo_commands = false; + bool print_results = false; + + HandleCommandsFromFile (init_file, exe_ctx, stop_on_continue, stop_on_error, echo_commands, print_results, eLazyBoolNo, result); + } + else + { + // nothing to be done if the file doesn't exist + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } +} + +PlatformSP +CommandInterpreter::GetPlatform (bool prefer_target_platform) +{ + PlatformSP platform_sp; + if (prefer_target_platform) + { + ExecutionContext exe_ctx(GetExecutionContext()); + Target *target = exe_ctx.GetTargetPtr(); + if (target) + platform_sp = target->GetPlatform(); + } + + if (!platform_sp) + platform_sp = m_debugger.GetPlatformList().GetSelectedPlatform(); + return platform_sp; +} + +void +CommandInterpreter::HandleCommands (const StringList &commands, + ExecutionContext *override_context, + bool stop_on_continue, + bool stop_on_error, + bool echo_commands, + bool print_results, + LazyBool add_to_history, + CommandReturnObject &result) +{ + size_t num_lines = commands.GetSize(); + + // If we are going to continue past a "continue" then we need to run the commands synchronously. + // Make sure you reset this value anywhere you return from the function. + + bool old_async_execution = m_debugger.GetAsyncExecution(); + + // If we've been given an execution context, set it at the start, but don't keep resetting it or we will + // cause series of commands that change the context, then do an operation that relies on that context to fail. + + if (override_context != NULL) + UpdateExecutionContext (override_context); + + if (!stop_on_continue) + { + m_debugger.SetAsyncExecution (false); + } + + for (size_t idx = 0; idx < num_lines; idx++) + { + const char *cmd = commands.GetStringAtIndex(idx); + if (cmd[0] == '\0') + continue; + + if (echo_commands) + { + result.AppendMessageWithFormat ("%s %s\n", + GetPrompt(), + cmd); + } + + CommandReturnObject tmp_result; + // If override_context is not NULL, pass no_context_switching = true for + // HandleCommand() since we updated our context already. + + // We might call into a regex or alias command, in which case the add_to_history will get lost. This + // m_command_source_depth dingus is the way we turn off adding to the history in that case, so set it up here. + if (!add_to_history) + m_command_source_depth++; + bool success = HandleCommand(cmd, add_to_history, tmp_result, + NULL, /* override_context */ + true, /* repeat_on_empty_command */ + override_context != NULL /* no_context_switching */); + if (!add_to_history) + m_command_source_depth--; + + if (print_results) + { + if (tmp_result.Succeeded()) + result.AppendMessageWithFormat("%s", tmp_result.GetOutputData()); + } + + if (!success || !tmp_result.Succeeded()) + { + const char *error_msg = tmp_result.GetErrorData(); + if (error_msg == NULL || error_msg[0] == '\0') + error_msg = "<unknown error>.\n"; + if (stop_on_error) + { + result.AppendErrorWithFormat("Aborting reading of commands after command #%zu: '%s' failed with %s", + idx, cmd, error_msg); + result.SetStatus (eReturnStatusFailed); + m_debugger.SetAsyncExecution (old_async_execution); + return; + } + else if (print_results) + { + result.AppendMessageWithFormat ("Command #%zu '%s' failed with %s", + idx + 1, + cmd, + error_msg); + } + } + + if (result.GetImmediateOutputStream()) + result.GetImmediateOutputStream()->Flush(); + + if (result.GetImmediateErrorStream()) + result.GetImmediateErrorStream()->Flush(); + + // N.B. Can't depend on DidChangeProcessState, because the state coming into the command execution + // could be running (for instance in Breakpoint Commands. + // So we check the return value to see if it is has running in it. + if ((tmp_result.GetStatus() == eReturnStatusSuccessContinuingNoResult) + || (tmp_result.GetStatus() == eReturnStatusSuccessContinuingResult)) + { + if (stop_on_continue) + { + // If we caused the target to proceed, and we're going to stop in that case, set the + // status in our real result before returning. This is an error if the continue was not the + // last command in the set of commands to be run. + if (idx != num_lines - 1) + result.AppendErrorWithFormat("Aborting reading of commands after command #%zu: '%s' continued the target.\n", + idx + 1, cmd); + else + result.AppendMessageWithFormat ("Command #%zu '%s' continued the target.\n", idx + 1, cmd); + + result.SetStatus(tmp_result.GetStatus()); + m_debugger.SetAsyncExecution (old_async_execution); + + return; + } + } + + } + + result.SetStatus (eReturnStatusSuccessFinishResult); + m_debugger.SetAsyncExecution (old_async_execution); + + return; +} + +void +CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file, + ExecutionContext *context, + bool stop_on_continue, + bool stop_on_error, + bool echo_command, + bool print_result, + LazyBool add_to_history, + CommandReturnObject &result) +{ + if (cmd_file.Exists()) + { + bool success; + StringList commands; + success = commands.ReadFileLines(cmd_file); + if (!success) + { + result.AppendErrorWithFormat ("Error reading commands from file: %s.\n", cmd_file.GetFilename().AsCString()); + result.SetStatus (eReturnStatusFailed); + return; + } + m_command_source_depth++; + HandleCommands (commands, context, stop_on_continue, stop_on_error, echo_command, print_result, add_to_history, result); + m_command_source_depth--; + } + else + { + result.AppendErrorWithFormat ("Error reading commands from file %s - file not found.\n", + cmd_file.GetFilename().AsCString()); + result.SetStatus (eReturnStatusFailed); + return; + } +} + +ScriptInterpreter * +CommandInterpreter::GetScriptInterpreter (bool can_create) +{ + if (m_script_interpreter_ap.get() != NULL) + return m_script_interpreter_ap.get(); + + if (!can_create) + return NULL; + + // <rdar://problem/11751427> + // we need to protect the initialization of the script interpreter + // otherwise we could end up with two threads both trying to create + // their instance of it, and for some languages (e.g. Python) + // this is a bulletproof recipe for disaster! + // this needs to be a function-level static because multiple Debugger instances living in the same process + // still need to be isolated and not try to initialize Python concurrently + static Mutex g_interpreter_mutex(Mutex::eMutexTypeRecursive); + Mutex::Locker interpreter_lock(g_interpreter_mutex); + + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("Initializing the ScriptInterpreter now\n"); + + lldb::ScriptLanguage script_lang = GetDebugger().GetScriptLanguage(); + switch (script_lang) + { + case eScriptLanguagePython: +#ifndef LLDB_DISABLE_PYTHON + m_script_interpreter_ap.reset (new ScriptInterpreterPython (*this)); + break; +#else + // Fall through to the None case when python is disabled +#endif + case eScriptLanguageNone: + m_script_interpreter_ap.reset (new ScriptInterpreterNone (*this)); + break; + }; + + return m_script_interpreter_ap.get(); +} + + + +bool +CommandInterpreter::GetSynchronous () +{ + return m_synchronous_execution; +} + +void +CommandInterpreter::SetSynchronous (bool value) +{ + m_synchronous_execution = value; +} + +void +CommandInterpreter::OutputFormattedHelpText (Stream &strm, + const char *word_text, + const char *separator, + const char *help_text, + size_t max_word_len) +{ + const uint32_t max_columns = m_debugger.GetTerminalWidth(); + + int indent_size = max_word_len + strlen (separator) + 2; + + strm.IndentMore (indent_size); + + StreamString text_strm; + text_strm.Printf ("%-*s %s %s", (int)max_word_len, word_text, separator, help_text); + + size_t len = text_strm.GetSize(); + const char *text = text_strm.GetData(); + if (text[len - 1] == '\n') + { + text_strm.EOL(); + len = text_strm.GetSize(); + } + + if (len < max_columns) + { + // Output it as a single line. + strm.Printf ("%s", text); + } + else + { + // We need to break it up into multiple lines. + bool first_line = true; + int text_width; + size_t start = 0; + size_t end = start; + const size_t final_end = strlen (text); + + while (end < final_end) + { + if (first_line) + text_width = max_columns - 1; + else + text_width = max_columns - indent_size - 1; + + // Don't start the 'text' on a space, since we're already outputting the indentation. + if (!first_line) + { + while ((start < final_end) && (text[start] == ' ')) + start++; + } + + end = start + text_width; + if (end > final_end) + end = final_end; + else + { + // 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') + end--; + assert (end > 0); + } + + const size_t sub_len = end - start; + if (start != 0) + strm.EOL(); + if (!first_line) + strm.Indent(); + else + first_line = false; + assert (start <= final_end); + assert (start + sub_len <= final_end); + if (sub_len > 0) + strm.Write (text + start, sub_len); + start = end + 1; + } + } + strm.EOL(); + strm.IndentLess(indent_size); +} + +void +CommandInterpreter::OutputHelpText (Stream &strm, + const char *word_text, + const char *separator, + const char *help_text, + uint32_t max_word_len) +{ + int indent_size = max_word_len + strlen (separator) + 2; + + strm.IndentMore (indent_size); + + StreamString text_strm; + text_strm.Printf ("%-*s %s %s", max_word_len, word_text, separator, help_text); + + const uint32_t max_columns = m_debugger.GetTerminalWidth(); + + size_t len = text_strm.GetSize(); + const char *text = text_strm.GetData(); + + uint32_t chars_left = max_columns; + + for (uint32_t i = 0; i < len; i++) + { + if ((text[i] == ' ' && ::strchr((text+i+1), ' ') && chars_left < ::strchr((text+i+1), ' ')-(text+i)) || text[i] == '\n') + { + chars_left = max_columns - indent_size; + strm.EOL(); + strm.Indent(); + } + else + { + strm.PutChar(text[i]); + chars_left--; + } + + } + + strm.EOL(); + strm.IndentLess(indent_size); +} + +void +CommandInterpreter::FindCommandsForApropos (const char *search_word, StringList &commands_found, + StringList &commands_help, bool search_builtin_commands, bool search_user_commands) +{ + CommandObject::CommandMap::const_iterator pos; + + if (search_builtin_commands) + { + for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) + { + const char *command_name = pos->first.c_str(); + CommandObject *cmd_obj = pos->second.get(); + + if (cmd_obj->HelpTextContainsWord (search_word)) + { + commands_found.AppendString (command_name); + commands_help.AppendString (cmd_obj->GetHelp()); + } + + if (cmd_obj->IsMultiwordObject()) + cmd_obj->AproposAllSubCommands (command_name, + search_word, + commands_found, + commands_help); + + } + } + + if (search_user_commands) + { + for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) + { + const char *command_name = pos->first.c_str(); + CommandObject *cmd_obj = pos->second.get(); + + if (cmd_obj->HelpTextContainsWord (search_word)) + { + commands_found.AppendString (command_name); + commands_help.AppendString (cmd_obj->GetHelp()); + } + + if (cmd_obj->IsMultiwordObject()) + cmd_obj->AproposAllSubCommands (command_name, + search_word, + commands_found, + commands_help); + + } + } +} + + +void +CommandInterpreter::UpdateExecutionContext (ExecutionContext *override_context) +{ + if (override_context != NULL) + { + m_exe_ctx_ref = *override_context; + } + else + { + const bool adopt_selected = true; + m_exe_ctx_ref.SetTargetPtr (m_debugger.GetSelectedTarget().get(), adopt_selected); + } +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp new file mode 100644 index 0000000..291dc40 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp @@ -0,0 +1,1174 @@ +//===-- CommandObject.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/lldb-python.h" + +#include "lldb/Interpreter/CommandObject.h" + +#include <string> +#include <map> + +#include <getopt.h> +#include <stdlib.h> +#include <ctype.h> + +#include "lldb/Core/Address.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Interpreter/Options.h" + +// These are for the Sourcename completers. +// FIXME: Make a separate file for the completers. +#include "lldb/Host/FileSpec.h" +#include "lldb/Core/FileSpecList.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Interpreter/ScriptInterpreterPython.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObject +//------------------------------------------------------------------------- + +CommandObject::CommandObject +( + CommandInterpreter &interpreter, + const char *name, + const char *help, + const char *syntax, + uint32_t flags +) : + m_interpreter (interpreter), + m_cmd_name (name), + m_cmd_help_short (), + m_cmd_help_long (), + m_cmd_syntax (), + m_is_alias (false), + m_flags (flags), + m_arguments(), + m_command_override_callback (NULL), + m_command_override_baton (NULL) +{ + if (help && help[0]) + m_cmd_help_short = help; + if (syntax && syntax[0]) + m_cmd_syntax = syntax; +} + +CommandObject::~CommandObject () +{ +} + +const char * +CommandObject::GetHelp () +{ + return m_cmd_help_short.c_str(); +} + +const char * +CommandObject::GetHelpLong () +{ + return m_cmd_help_long.c_str(); +} + +const char * +CommandObject::GetSyntax () +{ + if (m_cmd_syntax.length() == 0) + { + StreamString syntax_str; + syntax_str.Printf ("%s", GetCommandName()); + if (GetOptions() != NULL) + syntax_str.Printf (" <cmd-options>"); + if (m_arguments.size() > 0) + { + syntax_str.Printf (" "); + if (WantsRawCommandString() && GetOptions() && GetOptions()->NumCommandOptions()) + syntax_str.Printf("-- "); + GetFormattedCommandArguments (syntax_str); + } + m_cmd_syntax = syntax_str.GetData (); + } + + return m_cmd_syntax.c_str(); +} + +const char * +CommandObject::GetCommandName () +{ + return m_cmd_name.c_str(); +} + +void +CommandObject::SetCommandName (const char *name) +{ + m_cmd_name = name; +} + +void +CommandObject::SetHelp (const char *cstr) +{ + m_cmd_help_short = cstr; +} + +void +CommandObject::SetHelpLong (const char *cstr) +{ + m_cmd_help_long = cstr; +} + +void +CommandObject::SetHelpLong (std::string str) +{ + m_cmd_help_long = str; +} + +void +CommandObject::SetSyntax (const char *cstr) +{ + m_cmd_syntax = cstr; +} + +Options * +CommandObject::GetOptions () +{ + // By default commands don't have options unless this virtual function + // is overridden by base classes. + return NULL; +} + +bool +CommandObject::ParseOptions +( + Args& args, + CommandReturnObject &result +) +{ + // See if the subclass has options? + Options *options = GetOptions(); + if (options != NULL) + { + Error error; + options->NotifyOptionParsingStarting(); + + // ParseOptions calls getopt_long_only, which always skips the zero'th item in the array and starts at position 1, + // so we need to push a dummy value into position zero. + args.Unshift("dummy_string"); + error = args.ParseOptions (*options); + + // The "dummy_string" will have already been removed by ParseOptions, + // so no need to remove it. + + if (error.Success()) + error = options->NotifyOptionParsingFinished(); + + if (error.Success()) + { + if (options->VerifyOptions (result)) + return true; + } + else + { + const char *error_cstr = error.AsCString(); + if (error_cstr) + { + // We got an error string, lets use that + result.AppendError(error_cstr); + } + else + { + // No error string, output the usage information into result + options->GenerateOptionUsage (result.GetErrorStream(), this); + } + } + result.SetStatus (eReturnStatusFailed); + return false; + } + return true; +} + + + +bool +CommandObject::CheckRequirements (CommandReturnObject &result) +{ +#ifdef LLDB_CONFIGURATION_DEBUG + // Nothing should be stored in m_exe_ctx between running commands as m_exe_ctx + // has shared pointers to the target, process, thread and frame and we don't + // want any CommandObject instances to keep any of these objects around + // longer than for a single command. Every command should call + // CommandObject::Cleanup() after it has completed + assert (m_exe_ctx.GetTargetPtr() == NULL); + assert (m_exe_ctx.GetProcessPtr() == NULL); + assert (m_exe_ctx.GetThreadPtr() == NULL); + assert (m_exe_ctx.GetFramePtr() == NULL); +#endif + + // Lock down the interpreter's execution context prior to running the + // command so we guarantee the selected target, process, thread and frame + // can't go away during the execution + m_exe_ctx = m_interpreter.GetExecutionContext(); + + const uint32_t flags = GetFlags().Get(); + if (flags & (eFlagRequiresTarget | + eFlagRequiresProcess | + eFlagRequiresThread | + eFlagRequiresFrame | + eFlagTryTargetAPILock )) + { + + if ((flags & eFlagRequiresTarget) && !m_exe_ctx.HasTargetScope()) + { + result.AppendError (GetInvalidTargetDescription()); + return false; + } + + if ((flags & eFlagRequiresProcess) && !m_exe_ctx.HasProcessScope()) + { + result.AppendError (GetInvalidProcessDescription()); + return false; + } + + if ((flags & eFlagRequiresThread) && !m_exe_ctx.HasThreadScope()) + { + result.AppendError (GetInvalidThreadDescription()); + return false; + } + + if ((flags & eFlagRequiresFrame) && !m_exe_ctx.HasFrameScope()) + { + result.AppendError (GetInvalidFrameDescription()); + return false; + } + + if ((flags & eFlagRequiresRegContext) && (m_exe_ctx.GetRegisterContext() == NULL)) + { + result.AppendError (GetInvalidRegContextDescription()); + return false; + } + + if (flags & eFlagTryTargetAPILock) + { + Target *target = m_exe_ctx.GetTargetPtr(); + if (target) + { + if (m_api_locker.TryLock (target->GetAPIMutex(), NULL) == false) + { + result.AppendError ("failed to get API lock"); + return false; + } + } + } + } + + if (GetFlags().AnySet (CommandObject::eFlagProcessMustBeLaunched | CommandObject::eFlagProcessMustBePaused)) + { + Process *process = m_interpreter.GetExecutionContext().GetProcessPtr(); + if (process == NULL) + { + // A process that is not running is considered paused. + if (GetFlags().Test(CommandObject::eFlagProcessMustBeLaunched)) + { + result.AppendError ("Process must exist."); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + StateType state = process->GetState(); + switch (state) + { + case eStateInvalid: + case eStateSuspended: + case eStateCrashed: + case eStateStopped: + break; + + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateDetached: + case eStateExited: + case eStateUnloaded: + if (GetFlags().Test(CommandObject::eFlagProcessMustBeLaunched)) + { + result.AppendError ("Process must be launched."); + result.SetStatus (eReturnStatusFailed); + return false; + } + break; + + case eStateRunning: + case eStateStepping: + if (GetFlags().Test(CommandObject::eFlagProcessMustBePaused)) + { + result.AppendError ("Process is running. Use 'process interrupt' to pause execution."); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + } + } + return true; +} + +void +CommandObject::Cleanup () +{ + m_exe_ctx.Clear(); + m_api_locker.Unlock(); +} + + +class CommandDictCommandPartialMatch +{ + public: + CommandDictCommandPartialMatch (const char *match_str) + { + m_match_str = match_str; + } + bool operator() (const std::pair<std::string, lldb::CommandObjectSP> map_element) const + { + // A NULL or empty string matches everything. + if (m_match_str == NULL || *m_match_str == '\0') + return true; + + return map_element.first.find (m_match_str, 0) == 0; + } + + private: + const char *m_match_str; +}; + +int +CommandObject::AddNamesMatchingPartialString (CommandObject::CommandMap &in_map, const char *cmd_str, + StringList &matches) +{ + int number_added = 0; + CommandDictCommandPartialMatch matcher(cmd_str); + + CommandObject::CommandMap::iterator matching_cmds = std::find_if (in_map.begin(), in_map.end(), matcher); + + while (matching_cmds != in_map.end()) + { + ++number_added; + matches.AppendString((*matching_cmds).first.c_str()); + matching_cmds = std::find_if (++matching_cmds, in_map.end(), matcher);; + } + return number_added; +} + +int +CommandObject::HandleCompletion +( + Args &input, + int &cursor_index, + int &cursor_char_position, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches +) +{ + // Default implmentation of WantsCompletion() is !WantsRawCommandString(). + // Subclasses who want raw command string but desire, for example, + // argument completion should override WantsCompletion() to return true, + // instead. + if (WantsRawCommandString() && !WantsCompletion()) + { + // FIXME: Abstract telling the completion to insert the completion character. + matches.Clear(); + return -1; + } + else + { + // Can we do anything generic with the options? + Options *cur_options = GetOptions(); + CommandReturnObject result; + OptionElementVector opt_element_vector; + + if (cur_options != NULL) + { + // Re-insert the dummy command name string which will have been + // stripped off: + input.Unshift ("dummy-string"); + cursor_index++; + + + // I stick an element on the end of the input, because if the last element is + // option that requires an argument, getopt_long_only will freak out. + + input.AppendArgument ("<FAKE-VALUE>"); + + input.ParseArgsForCompletion (*cur_options, opt_element_vector, cursor_index); + + input.DeleteArgumentAtIndex(input.GetArgumentCount() - 1); + + bool handled_by_options; + handled_by_options = cur_options->HandleOptionCompletion (input, + opt_element_vector, + cursor_index, + cursor_char_position, + match_start_point, + max_return_elements, + word_complete, + matches); + if (handled_by_options) + return matches.GetSize(); + } + + // If we got here, the last word is not an option or an option argument. + return HandleArgumentCompletion (input, + cursor_index, + cursor_char_position, + opt_element_vector, + match_start_point, + max_return_elements, + word_complete, + matches); + } +} + +bool +CommandObject::HelpTextContainsWord (const char *search_word) +{ + std::string options_usage_help; + + bool found_word = false; + + const char *short_help = GetHelp(); + const char *long_help = GetHelpLong(); + const char *syntax_help = GetSyntax(); + + if (short_help && strcasestr (short_help, search_word)) + found_word = true; + else if (long_help && strcasestr (long_help, search_word)) + found_word = true; + else if (syntax_help && strcasestr (syntax_help, search_word)) + found_word = true; + + if (!found_word + && GetOptions() != NULL) + { + StreamString usage_help; + GetOptions()->GenerateOptionUsage (usage_help, this); + if (usage_help.GetSize() > 0) + { + const char *usage_text = usage_help.GetData(); + if (strcasestr (usage_text, search_word)) + found_word = true; + } + } + + return found_word; +} + +int +CommandObject::GetNumArgumentEntries () +{ + return m_arguments.size(); +} + +CommandObject::CommandArgumentEntry * +CommandObject::GetArgumentEntryAtIndex (int idx) +{ + if (idx < m_arguments.size()) + return &(m_arguments[idx]); + + return NULL; +} + +CommandObject::ArgumentTableEntry * +CommandObject::FindArgumentDataByType (CommandArgumentType arg_type) +{ + const ArgumentTableEntry *table = CommandObject::GetArgumentTable(); + + for (int i = 0; i < eArgTypeLastArg; ++i) + if (table[i].arg_type == arg_type) + return (ArgumentTableEntry *) &(table[i]); + + return NULL; +} + +void +CommandObject::GetArgumentHelp (Stream &str, CommandArgumentType arg_type, CommandInterpreter &interpreter) +{ + const ArgumentTableEntry* table = CommandObject::GetArgumentTable(); + ArgumentTableEntry *entry = (ArgumentTableEntry *) &(table[arg_type]); + + // The table is *supposed* to be kept in arg_type order, but someone *could* have messed it up... + + if (entry->arg_type != arg_type) + entry = CommandObject::FindArgumentDataByType (arg_type); + + if (!entry) + return; + + StreamString name_str; + name_str.Printf ("<%s>", entry->arg_name); + + if (entry->help_function) + { + const char* help_text = entry->help_function(); + if (!entry->help_function.self_formatting) + { + interpreter.OutputFormattedHelpText (str, name_str.GetData(), "--", help_text, + name_str.GetSize()); + } + else + { + interpreter.OutputHelpText(str, name_str.GetData(), "--", help_text, + name_str.GetSize()); + } + } + else + interpreter.OutputFormattedHelpText (str, name_str.GetData(), "--", entry->help_text, name_str.GetSize()); +} + +const char * +CommandObject::GetArgumentName (CommandArgumentType arg_type) +{ + ArgumentTableEntry *entry = (ArgumentTableEntry *) &(CommandObject::GetArgumentTable()[arg_type]); + + // The table is *supposed* to be kept in arg_type order, but someone *could* have messed it up... + + if (entry->arg_type != arg_type) + entry = CommandObject::FindArgumentDataByType (arg_type); + + if (entry) + return entry->arg_name; + + StreamString str; + str << "Arg name for type (" << arg_type << ") not in arg table!"; + return str.GetData(); +} + +bool +CommandObject::IsPairType (ArgumentRepetitionType arg_repeat_type) +{ + if ((arg_repeat_type == eArgRepeatPairPlain) + || (arg_repeat_type == eArgRepeatPairOptional) + || (arg_repeat_type == eArgRepeatPairPlus) + || (arg_repeat_type == eArgRepeatPairStar) + || (arg_repeat_type == eArgRepeatPairRange) + || (arg_repeat_type == eArgRepeatPairRangeOptional)) + return true; + + return false; +} + +static CommandObject::CommandArgumentEntry +OptSetFiltered(uint32_t opt_set_mask, CommandObject::CommandArgumentEntry &cmd_arg_entry) +{ + CommandObject::CommandArgumentEntry ret_val; + for (unsigned i = 0; i < cmd_arg_entry.size(); ++i) + if (opt_set_mask & cmd_arg_entry[i].arg_opt_set_association) + ret_val.push_back(cmd_arg_entry[i]); + return ret_val; +} + +// Default parameter value of opt_set_mask is LLDB_OPT_SET_ALL, which means take +// all the argument data into account. On rare cases where some argument sticks +// with certain option sets, this function returns the option set filtered args. +void +CommandObject::GetFormattedCommandArguments (Stream &str, uint32_t opt_set_mask) +{ + int num_args = m_arguments.size(); + for (int i = 0; i < num_args; ++i) + { + if (i > 0) + str.Printf (" "); + CommandArgumentEntry arg_entry = + opt_set_mask == LLDB_OPT_SET_ALL ? m_arguments[i] + : OptSetFiltered(opt_set_mask, m_arguments[i]); + int num_alternatives = arg_entry.size(); + + if ((num_alternatives == 2) + && IsPairType (arg_entry[0].arg_repetition)) + { + const char *first_name = GetArgumentName (arg_entry[0].arg_type); + const char *second_name = GetArgumentName (arg_entry[1].arg_type); + switch (arg_entry[0].arg_repetition) + { + case eArgRepeatPairPlain: + str.Printf ("<%s> <%s>", first_name, second_name); + break; + case eArgRepeatPairOptional: + str.Printf ("[<%s> <%s>]", first_name, second_name); + break; + case eArgRepeatPairPlus: + str.Printf ("<%s> <%s> [<%s> <%s> [...]]", first_name, second_name, first_name, second_name); + break; + case eArgRepeatPairStar: + str.Printf ("[<%s> <%s> [<%s> <%s> [...]]]", first_name, second_name, first_name, second_name); + break; + case eArgRepeatPairRange: + str.Printf ("<%s_1> <%s_1> ... <%s_n> <%s_n>", first_name, second_name, first_name, second_name); + break; + case eArgRepeatPairRangeOptional: + str.Printf ("[<%s_1> <%s_1> ... <%s_n> <%s_n>]", first_name, second_name, first_name, second_name); + break; + // Explicitly test for all the rest of the cases, so if new types get added we will notice the + // missing case statement(s). + case eArgRepeatPlain: + case eArgRepeatOptional: + case eArgRepeatPlus: + case eArgRepeatStar: + case eArgRepeatRange: + // These should not be reached, as they should fail the IsPairType test above. + break; + } + } + else + { + StreamString names; + for (int j = 0; j < num_alternatives; ++j) + { + if (j > 0) + names.Printf (" | "); + names.Printf ("%s", GetArgumentName (arg_entry[j].arg_type)); + } + switch (arg_entry[0].arg_repetition) + { + case eArgRepeatPlain: + str.Printf ("<%s>", names.GetData()); + break; + case eArgRepeatPlus: + str.Printf ("<%s> [<%s> [...]]", names.GetData(), names.GetData()); + break; + case eArgRepeatStar: + str.Printf ("[<%s> [<%s> [...]]]", names.GetData(), names.GetData()); + break; + case eArgRepeatOptional: + str.Printf ("[<%s>]", names.GetData()); + break; + case eArgRepeatRange: + str.Printf ("<%s_1> .. <%s_n>", names.GetData(), names.GetData()); + break; + // Explicitly test for all the rest of the cases, so if new types get added we will notice the + // missing case statement(s). + case eArgRepeatPairPlain: + case eArgRepeatPairOptional: + case eArgRepeatPairPlus: + case eArgRepeatPairStar: + case eArgRepeatPairRange: + case eArgRepeatPairRangeOptional: + // These should not be hit, as they should pass the IsPairType test above, and control should + // have gone into the other branch of the if statement. + break; + } + } + } +} + +CommandArgumentType +CommandObject::LookupArgumentName (const char *arg_name) +{ + CommandArgumentType return_type = eArgTypeLastArg; + + std::string arg_name_str (arg_name); + size_t len = arg_name_str.length(); + if (arg_name[0] == '<' + && arg_name[len-1] == '>') + arg_name_str = arg_name_str.substr (1, len-2); + + const ArgumentTableEntry *table = GetArgumentTable(); + for (int i = 0; i < eArgTypeLastArg; ++i) + if (arg_name_str.compare (table[i].arg_name) == 0) + return_type = g_arguments_data[i].arg_type; + + return return_type; +} + +static const char * +RegisterNameHelpTextCallback () +{ + return "Register names can be specified using the architecture specific names. " + "They can also be specified using generic names. Not all generic entities have " + "registers backing them on all architectures. When they don't the generic name " + "will return an error.\n" + "The generic names defined in lldb are:\n" + "\n" + "pc - program counter register\n" + "ra - return address register\n" + "fp - frame pointer register\n" + "sp - stack pointer register\n" + "flags - the flags register\n" + "arg{1-6} - integer argument passing registers.\n"; +} + +static const char * +BreakpointIDHelpTextCallback () +{ + return "Breakpoint ID's consist major and minor numbers; the major number " + "corresponds to the single entity that was created with a 'breakpoint set' " + "command; the minor numbers correspond to all the locations that were actually " + "found/set based on the major breakpoint. A full breakpoint ID might look like " + "3.14, meaning the 14th location set for the 3rd breakpoint. You can specify " + "all the locations of a breakpoint by just indicating the major breakpoint " + "number. A valid breakpoint id consists either of just the major id number, " + "or the major number, a dot, and the location number (e.g. 3 or 3.2 could " + "both be valid breakpoint ids)."; +} + +static const char * +BreakpointIDRangeHelpTextCallback () +{ + return "A 'breakpoint id list' is a manner of specifying multiple breakpoints. " + "This can be done through several mechanisms. The easiest way is to just " + "enter a space-separated list of breakpoint ids. To specify all the " + "breakpoint locations under a major breakpoint, you can use the major " + "breakpoint number followed by '.*', eg. '5.*' means all the locations under " + "breakpoint 5. You can also indicate a range of breakpoints by using " + "<start-bp-id> - <end-bp-id>. The start-bp-id and end-bp-id for a range can " + "be any valid breakpoint ids. It is not legal, however, to specify a range " + "using specific locations that cross major breakpoint numbers. I.e. 3.2 - 3.7" + " is legal; 2 - 5 is legal; but 3.2 - 4.4 is not legal."; +} + +static const char * +GDBFormatHelpTextCallback () +{ + return "A GDB format consists of a repeat count, a format letter and a size letter. " + "The repeat count is optional and defaults to 1. The format letter is optional " + "and defaults to the previous format that was used. The size letter is optional " + "and defaults to the previous size that was used.\n" + "\n" + "Format letters include:\n" + "o - octal\n" + "x - hexadecimal\n" + "d - decimal\n" + "u - unsigned decimal\n" + "t - binary\n" + "f - float\n" + "a - address\n" + "i - instruction\n" + "c - char\n" + "s - string\n" + "T - OSType\n" + "A - float as hex\n" + "\n" + "Size letters include:\n" + "b - 1 byte (byte)\n" + "h - 2 bytes (halfword)\n" + "w - 4 bytes (word)\n" + "g - 8 bytes (giant)\n" + "\n" + "Example formats:\n" + "32xb - show 32 1 byte hexadecimal integer values\n" + "16xh - show 16 2 byte hexadecimal integer values\n" + "64 - show 64 2 byte hexadecimal integer values (format and size from the last format)\n" + "dw - show 1 4 byte decimal integer value\n" + ; +} + +static const char * +FormatHelpTextCallback () +{ + + static char* help_text_ptr = NULL; + + if (help_text_ptr) + return help_text_ptr; + + StreamString sstr; + sstr << "One of the format names (or one-character names) that can be used to show a variable's value:\n"; + for (Format f = eFormatDefault; f < kNumFormats; f = Format(f+1)) + { + if (f != eFormatDefault) + sstr.PutChar('\n'); + + char format_char = FormatManager::GetFormatAsFormatChar(f); + if (format_char) + sstr.Printf("'%c' or ", format_char); + + sstr.Printf ("\"%s\"", FormatManager::GetFormatAsCString(f)); + } + + sstr.Flush(); + + std::string data = sstr.GetString(); + + help_text_ptr = new char[data.length()+1]; + + data.copy(help_text_ptr, data.length()); + + return help_text_ptr; +} + +static const char * +LanguageTypeHelpTextCallback () +{ + static char* help_text_ptr = NULL; + + if (help_text_ptr) + return help_text_ptr; + + StreamString sstr; + sstr << "One of the following languages:\n"; + + for (unsigned int l = eLanguageTypeUnknown; l < eNumLanguageTypes; ++l) + { + sstr << " " << LanguageRuntime::GetNameForLanguageType(static_cast<LanguageType>(l)) << "\n"; + } + + sstr.Flush(); + + std::string data = sstr.GetString(); + + help_text_ptr = new char[data.length()+1]; + + data.copy(help_text_ptr, data.length()); + + return help_text_ptr; +} + +static const char * +SummaryStringHelpTextCallback() +{ + return + "A summary string is a way to extract information from variables in order to present them using a summary.\n" + "Summary strings contain static text, variables, scopes and control sequences:\n" + " - Static text can be any sequence of non-special characters, i.e. anything but '{', '}', '$', or '\\'.\n" + " - Variables are sequences of characters beginning with ${, ending with } and that contain symbols in the format described below.\n" + " - Scopes are any sequence of text between { and }. Anything included in a scope will only appear in the output summary if there were no errors.\n" + " - Control sequences are the usual C/C++ '\\a', '\\n', ..., plus '\\$', '\\{' and '\\}'.\n" + "A summary string works by copying static text verbatim, turning control sequences into their character counterpart, expanding variables and trying to expand scopes.\n" + "A variable is expanded by giving it a value other than its textual representation, and the way this is done depends on what comes after the ${ marker.\n" + "The most common sequence if ${var followed by an expression path, which is the text one would type to access a member of an aggregate types, given a variable of that type" + " (e.g. if type T has a member named x, which has a member named y, and if t is of type T, the expression path would be .x.y and the way to fit that into a summary string would be" + " ${var.x.y}). You can also use ${*var followed by an expression path and in that case the object referred by the path will be dereferenced before being displayed." + " If the object is not a pointer, doing so will cause an error. For additional details on expression paths, you can type 'help expr-path'. \n" + "By default, summary strings attempt to display the summary for any variable they reference, and if that fails the value. If neither can be shown, nothing is displayed." + "In a summary string, you can also use an array index [n], or a slice-like range [n-m]. This can have two different meanings depending on what kind of object the expression" + " path refers to:\n" + " - if it is a scalar type (any basic type like int, float, ...) the expression is a bitfield, i.e. the bits indicated by the indexing operator are extracted out of the number" + " and displayed as an individual variable\n" + " - if it is an array or pointer the array items indicated by the indexing operator are shown as the result of the variable. if the expression is an array, real array items are" + " printed; if it is a pointer, the pointer-as-array syntax is used to obtain the values (this means, the latter case can have no range checking)\n" + "If you are trying to display an array for which the size is known, you can also use [] instead of giving an exact range. This has the effect of showing items 0 thru size - 1.\n" + "Additionally, a variable can contain an (optional) format code, as in ${var.x.y%code}, where code can be any of the valid formats described in 'help format', or one of the" + " special symbols only allowed as part of a variable:\n" + " %V: show the value of the object by default\n" + " %S: show the summary of the object by default\n" + " %@: show the runtime-provided object description (for Objective-C, it calls NSPrintForDebugger; for C/C++ it does nothing)\n" + " %L: show the location of the object (memory address or a register name)\n" + " %#: show the number of children of the object\n" + " %T: show the type of the object\n" + "Another variable that you can use in summary strings is ${svar . This sequence works exactly like ${var, including the fact that ${*svar is an allowed sequence, but uses" + " the object's synthetic children provider instead of the actual objects. For instance, if you are using STL synthetic children providers, the following summary string would" + " count the number of actual elements stored in an std::list:\n" + "type summary add -s \"${svar%#}\" -x \"std::list<\""; +} + +static const char * +ExprPathHelpTextCallback() +{ + return + "An expression path is the sequence of symbols that is used in C/C++ to access a member variable of an aggregate object (class).\n" + "For instance, given a class:\n" + " class foo {\n" + " int a;\n" + " int b; .\n" + " foo* next;\n" + " };\n" + "the expression to read item b in the item pointed to by next for foo aFoo would be aFoo.next->b.\n" + "Given that aFoo could just be any object of type foo, the string '.next->b' is the expression path, because it can be attached to any foo instance to achieve the effect.\n" + "Expression paths in LLDB include dot (.) and arrow (->) operators, and most commands using expression paths have ways to also accept the star (*) operator.\n" + "The meaning of these operators is the same as the usual one given to them by the C/C++ standards.\n" + "LLDB also has support for indexing ([ ]) in expression paths, and extends the traditional meaning of the square brackets operator to allow bitfield extraction:\n" + "for objects of native types (int, float, char, ...) saying '[n-m]' as an expression path (where n and m are any positive integers, e.g. [3-5]) causes LLDB to extract" + " bits n thru m from the value of the variable. If n == m, [n] is also allowed as a shortcut syntax. For arrays and pointers, expression paths can only contain one index" + " and the meaning of the operation is the same as the one defined by C/C++ (item extraction). Some commands extend bitfield-like syntax for arrays and pointers with the" + " meaning of array slicing (taking elements n thru m inside the array or pointed-to memory)."; +} + +void +CommandObject::GenerateHelpText (CommandReturnObject &result) +{ + GenerateHelpText(result.GetOutputStream()); + + result.SetStatus (eReturnStatusSuccessFinishNoResult); +} + +void +CommandObject::GenerateHelpText (Stream &output_strm) +{ + CommandInterpreter& interpreter = GetCommandInterpreter(); + if (GetOptions() != NULL) + { + if (WantsRawCommandString()) + { + std::string help_text (GetHelp()); + help_text.append (" This command takes 'raw' input (no need to quote stuff)."); + interpreter.OutputFormattedHelpText (output_strm, "", "", help_text.c_str(), 1); + } + else + interpreter.OutputFormattedHelpText (output_strm, "", "", GetHelp(), 1); + output_strm.Printf ("\nSyntax: %s\n", GetSyntax()); + GetOptions()->GenerateOptionUsage (output_strm, this); + const char *long_help = GetHelpLong(); + if ((long_help != NULL) + && (strlen (long_help) > 0)) + output_strm.Printf ("\n%s", long_help); + if (WantsRawCommandString() && !WantsCompletion()) + { + // Emit the message about using ' -- ' between the end of the command options and the raw input + // conditionally, i.e., only if the command object does not want completion. + interpreter.OutputFormattedHelpText (output_strm, "", "", + "\nIMPORTANT NOTE: Because this command takes 'raw' input, if you use any command options" + " you must use ' -- ' between the end of the command options and the beginning of the raw input.", 1); + } + else if (GetNumArgumentEntries() > 0 + && GetOptions() + && GetOptions()->NumCommandOptions() > 0) + { + // Also emit a warning about using "--" in case you are using a command that takes options and arguments. + interpreter.OutputFormattedHelpText (output_strm, "", "", + "\nThis command takes options and free-form arguments. If your arguments resemble" + " option specifiers (i.e., they start with a - or --), you must use ' -- ' between" + " the end of the command options and the beginning of the arguments.", 1); + } + } + else if (IsMultiwordObject()) + { + if (WantsRawCommandString()) + { + std::string help_text (GetHelp()); + help_text.append (" This command takes 'raw' input (no need to quote stuff)."); + interpreter.OutputFormattedHelpText (output_strm, "", "", help_text.c_str(), 1); + } + else + interpreter.OutputFormattedHelpText (output_strm, "", "", GetHelp(), 1); + GenerateHelpText (output_strm); + } + else + { + const char *long_help = GetHelpLong(); + if ((long_help != NULL) + && (strlen (long_help) > 0)) + output_strm.Printf ("%s", long_help); + else if (WantsRawCommandString()) + { + std::string help_text (GetHelp()); + help_text.append (" This command takes 'raw' input (no need to quote stuff)."); + interpreter.OutputFormattedHelpText (output_strm, "", "", help_text.c_str(), 1); + } + else + interpreter.OutputFormattedHelpText (output_strm, "", "", GetHelp(), 1); + output_strm.Printf ("\nSyntax: %s\n", GetSyntax()); + } +} + +void +CommandObject::AddIDsArgumentData(CommandArgumentEntry &arg, CommandArgumentType ID, CommandArgumentType IDRange) +{ + CommandArgumentData id_arg; + CommandArgumentData id_range_arg; + + // Create the first variant for the first (and only) argument for this command. + id_arg.arg_type = ID; + id_arg.arg_repetition = eArgRepeatOptional; + + // Create the second variant for the first (and only) argument for this command. + id_range_arg.arg_type = IDRange; + id_range_arg.arg_repetition = eArgRepeatOptional; + + // The first (and only) argument for this command could be either an id or an id_range. + // Push both variants into the entry for the first argument for this command. + arg.push_back(id_arg); + arg.push_back(id_range_arg); +} + +const char * +CommandObject::GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type) +{ + if (arg_type >=0 && arg_type < eArgTypeLastArg) + return g_arguments_data[arg_type].arg_name; + return NULL; + +} + +const char * +CommandObject::GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type) +{ + if (arg_type >=0 && arg_type < eArgTypeLastArg) + return g_arguments_data[arg_type].help_text; + return NULL; +} + +bool +CommandObjectParsed::Execute (const char *args_string, CommandReturnObject &result) +{ + CommandOverrideCallback command_callback = GetOverrideCallback(); + bool handled = false; + Args cmd_args (args_string); + if (command_callback) + { + Args full_args (GetCommandName ()); + full_args.AppendArguments(cmd_args); + handled = command_callback (GetOverrideCallbackBaton(), full_args.GetConstArgumentVector()); + } + if (!handled) + { + for (size_t i = 0; i < cmd_args.GetArgumentCount(); ++i) + { + const char *tmp_str = cmd_args.GetArgumentAtIndex (i); + if (tmp_str[0] == '`') // back-quote + cmd_args.ReplaceArgumentAtIndex (i, m_interpreter.ProcessEmbeddedScriptCommands (tmp_str)); + } + + if (CheckRequirements(result)) + { + if (ParseOptions (cmd_args, result)) + { + // Call the command-specific version of 'Execute', passing it the already processed arguments. + handled = DoExecute (cmd_args, result); + } + } + + Cleanup(); + } + return handled; +} + +bool +CommandObjectRaw::Execute (const char *args_string, CommandReturnObject &result) +{ + CommandOverrideCallback command_callback = GetOverrideCallback(); + bool handled = false; + if (command_callback) + { + std::string full_command (GetCommandName ()); + full_command += ' '; + full_command += args_string; + const char *argv[2] = { NULL, NULL }; + argv[0] = full_command.c_str(); + handled = command_callback (GetOverrideCallbackBaton(), argv); + } + if (!handled) + { + if (CheckRequirements(result)) + handled = DoExecute (args_string, result); + + Cleanup(); + } + return handled; +} + +static +const char *arch_helper() +{ + static StreamString g_archs_help; + if (g_archs_help.Empty()) + { + StringList archs; + ArchSpec::AutoComplete(NULL, archs); + g_archs_help.Printf("These are the supported architecture names:\n"); + archs.Join("\n", g_archs_help); + } + return g_archs_help.GetData(); +} + +CommandObject::ArgumentTableEntry +CommandObject::g_arguments_data[] = +{ + { eArgTypeAddress, "address", CommandCompletions::eNoCompletion, { NULL, false }, "A valid address in the target program's execution space." }, + { eArgTypeAddressOrExpression, "address-expression", CommandCompletions::eNoCompletion, { NULL, false }, "An expression that resolves to an address." }, + { eArgTypeAliasName, "alias-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of an abbreviation (alias) for a debugger command." }, + { eArgTypeAliasOptions, "options-for-aliased-command", CommandCompletions::eNoCompletion, { NULL, false }, "Command options to be used as part of an alias (abbreviation) definition. (See 'help commands alias' for more information.)" }, + { eArgTypeArchitecture, "arch", CommandCompletions::eArchitectureCompletion, { arch_helper, true }, "The architecture name, e.g. i386 or x86_64." }, + { eArgTypeBoolean, "boolean", CommandCompletions::eNoCompletion, { NULL, false }, "A Boolean value: 'true' or 'false'" }, + { eArgTypeBreakpointID, "breakpt-id", CommandCompletions::eNoCompletion, { BreakpointIDHelpTextCallback, false }, NULL }, + { eArgTypeBreakpointIDRange, "breakpt-id-list", CommandCompletions::eNoCompletion, { BreakpointIDRangeHelpTextCallback, false }, NULL }, + { eArgTypeByteSize, "byte-size", CommandCompletions::eNoCompletion, { NULL, false }, "Number of bytes to use." }, + { eArgTypeClassName, "class-name", CommandCompletions::eNoCompletion, { NULL, false }, "Then name of a class from the debug information in the program." }, + { eArgTypeCommandName, "cmd-name", CommandCompletions::eNoCompletion, { NULL, false }, "A debugger command (may be multiple words), without any options or arguments." }, + { eArgTypeCount, "count", CommandCompletions::eNoCompletion, { NULL, false }, "An unsigned integer." }, + { eArgTypeDirectoryName, "directory", CommandCompletions::eDiskDirectoryCompletion, { NULL, false }, "A directory name." }, + { eArgTypeDisassemblyFlavor, "disassembly-flavor", CommandCompletions::eNoCompletion, { NULL, false }, "A disassembly flavor recognized by your disassembly plugin. Currently the only valid options are \"att\" and \"intel\" for Intel targets" }, + { eArgTypeEndAddress, "end-address", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." }, + { eArgTypeExpression, "expr", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." }, + { eArgTypeExpressionPath, "expr-path", CommandCompletions::eNoCompletion, { ExprPathHelpTextCallback, true }, NULL }, + { eArgTypeExprFormat, "expression-format", CommandCompletions::eNoCompletion, { NULL, false }, "[ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ]" }, + { eArgTypeFilename, "filename", CommandCompletions::eDiskFileCompletion, { NULL, false }, "The name of a file (can include path)." }, + { eArgTypeFormat, "format", CommandCompletions::eNoCompletion, { FormatHelpTextCallback, true }, NULL }, + { eArgTypeFrameIndex, "frame-index", CommandCompletions::eNoCompletion, { NULL, false }, "Index into a thread's list of frames." }, + { eArgTypeFullName, "fullname", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." }, + { eArgTypeFunctionName, "function-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a function." }, + { eArgTypeFunctionOrSymbol, "function-or-symbol", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a function or symbol." }, + { eArgTypeGDBFormat, "gdb-format", CommandCompletions::eNoCompletion, { GDBFormatHelpTextCallback, true }, NULL }, + { eArgTypeIndex, "index", CommandCompletions::eNoCompletion, { NULL, false }, "An index into a list." }, + { eArgTypeLanguage, "language", CommandCompletions::eNoCompletion, { LanguageTypeHelpTextCallback, true }, NULL }, + { eArgTypeLineNum, "linenum", CommandCompletions::eNoCompletion, { NULL, false }, "Line number in a source file." }, + { eArgTypeLogCategory, "log-category", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a category within a log channel, e.g. all (try \"log list\" to see a list of all channels and their categories." }, + { eArgTypeLogChannel, "log-channel", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a log channel, e.g. process.gdb-remote (try \"log list\" to see a list of all channels and their categories)." }, + { eArgTypeMethod, "method", CommandCompletions::eNoCompletion, { NULL, false }, "A C++ method name." }, + { eArgTypeName, "name", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." }, + { eArgTypeNewPathPrefix, "new-path-prefix", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." }, + { eArgTypeNumLines, "num-lines", CommandCompletions::eNoCompletion, { NULL, false }, "The number of lines to use." }, + { eArgTypeNumberPerLine, "number-per-line", CommandCompletions::eNoCompletion, { NULL, false }, "The number of items per line to display." }, + { eArgTypeOffset, "offset", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." }, + { eArgTypeOldPathPrefix, "old-path-prefix", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." }, + { eArgTypeOneLiner, "one-line-command", CommandCompletions::eNoCompletion, { NULL, false }, "A command that is entered as a single line of text." }, + { eArgTypePid, "pid", CommandCompletions::eNoCompletion, { NULL, false }, "The process ID number." }, + { eArgTypePlugin, "plugin", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." }, + { eArgTypeProcessName, "process-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of the process." }, + { eArgTypePythonClass, "python-class", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a Python class." }, + { eArgTypePythonFunction, "python-function", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a Python function." }, + { eArgTypePythonScript, "python-script", CommandCompletions::eNoCompletion, { NULL, false }, "Source code written in Python." }, + { eArgTypeQueueName, "queue-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of the thread queue." }, + { eArgTypeRegisterName, "register-name", CommandCompletions::eNoCompletion, { RegisterNameHelpTextCallback, true }, NULL }, + { eArgTypeRegularExpression, "regular-expression", CommandCompletions::eNoCompletion, { NULL, false }, "A regular expression." }, + { eArgTypeRunArgs, "run-args", CommandCompletions::eNoCompletion, { NULL, false }, "Arguments to be passed to the target program when it starts executing." }, + { eArgTypeRunMode, "run-mode", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." }, + { eArgTypeScriptedCommandSynchronicity, "script-cmd-synchronicity", CommandCompletions::eNoCompletion, { NULL, false }, "The synchronicity to use to run scripted commands with regard to LLDB event system." }, + { eArgTypeScriptLang, "script-language", CommandCompletions::eNoCompletion, { NULL, false }, "The scripting language to be used for script-based commands. Currently only Python is valid." }, + { eArgTypeSearchWord, "search-word", CommandCompletions::eNoCompletion, { NULL, false }, "The word for which you wish to search for information about." }, + { eArgTypeSelector, "selector", CommandCompletions::eNoCompletion, { NULL, false }, "An Objective-C selector name." }, + { eArgTypeSettingIndex, "setting-index", CommandCompletions::eNoCompletion, { NULL, false }, "An index into a settings variable that is an array (try 'settings list' to see all the possible settings variables and their types)." }, + { eArgTypeSettingKey, "setting-key", CommandCompletions::eNoCompletion, { NULL, false }, "A key into a settings variables that is a dictionary (try 'settings list' to see all the possible settings variables and their types)." }, + { eArgTypeSettingPrefix, "setting-prefix", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a settable internal debugger variable up to a dot ('.'), e.g. 'target.process.'" }, + { eArgTypeSettingVariableName, "setting-variable-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a settable internal debugger variable. Type 'settings list' to see a complete list of such variables." }, + { eArgTypeShlibName, "shlib-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a shared library." }, + { eArgTypeSourceFile, "source-file", CommandCompletions::eSourceFileCompletion, { NULL, false }, "The name of a source file.." }, + { eArgTypeSortOrder, "sort-order", CommandCompletions::eNoCompletion, { NULL, false }, "Specify a sort order when dumping lists." }, + { eArgTypeStartAddress, "start-address", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." }, + { eArgTypeSummaryString, "summary-string", CommandCompletions::eNoCompletion, { SummaryStringHelpTextCallback, true }, NULL }, + { eArgTypeSymbol, "symbol", CommandCompletions::eSymbolCompletion, { NULL, false }, "Any symbol name (function name, variable, argument, etc.)" }, + { eArgTypeThreadID, "thread-id", CommandCompletions::eNoCompletion, { NULL, false }, "Thread ID number." }, + { eArgTypeThreadIndex, "thread-index", CommandCompletions::eNoCompletion, { NULL, false }, "Index into the process' list of threads." }, + { eArgTypeThreadName, "thread-name", CommandCompletions::eNoCompletion, { NULL, false }, "The thread's name." }, + { eArgTypeUnsignedInteger, "unsigned-integer", CommandCompletions::eNoCompletion, { NULL, false }, "An unsigned integer." }, + { eArgTypeUnixSignal, "unix-signal", CommandCompletions::eNoCompletion, { NULL, false }, "A valid Unix signal name or number (e.g. SIGKILL, KILL or 9)." }, + { eArgTypeVarName, "variable-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a variable in your program." }, + { eArgTypeValue, "value", CommandCompletions::eNoCompletion, { NULL, false }, "A value could be anything, depending on where and how it is used." }, + { eArgTypeWidth, "width", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." }, + { eArgTypeNone, "none", CommandCompletions::eNoCompletion, { NULL, false }, "No help available for this." }, + { eArgTypePlatform, "platform-name", CommandCompletions::ePlatformPluginCompletion, { NULL, false }, "The name of an installed platform plug-in . Type 'platform list' to see a complete list of installed platforms." }, + { eArgTypeWatchpointID, "watchpt-id", CommandCompletions::eNoCompletion, { NULL, false }, "Watchpoint IDs are positive integers." }, + { eArgTypeWatchpointIDRange, "watchpt-id-list", CommandCompletions::eNoCompletion, { NULL, false }, "For example, '1-3' or '1 to 3'." }, + { eArgTypeWatchType, "watch-type", CommandCompletions::eNoCompletion, { NULL, false }, "Specify the type for a watchpoint." } +}; + +const CommandObject::ArgumentTableEntry* +CommandObject::GetArgumentTable () +{ + // If this assertion fires, then the table above is out of date with the CommandArgumentType enumeration + assert ((sizeof (CommandObject::g_arguments_data) / sizeof (CommandObject::ArgumentTableEntry)) == eArgTypeLastArg); + return CommandObject::g_arguments_data; +} + + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandObjectRegexCommand.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandObjectRegexCommand.cpp new file mode 100644 index 0000000..59cf1f0 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandObjectRegexCommand.cpp @@ -0,0 +1,150 @@ +//===-- CommandObjectRegexCommand.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/lldb-python.h" + +#include "lldb/Interpreter/CommandObjectRegexCommand.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// CommandObjectRegexCommand constructor +//---------------------------------------------------------------------- +CommandObjectRegexCommand::CommandObjectRegexCommand +( + CommandInterpreter &interpreter, + const char *name, + const char *help, + const char *syntax, + uint32_t max_matches, + uint32_t completion_type_mask +) : + CommandObjectRaw (interpreter, name, help, syntax), + m_max_matches (max_matches), + m_completion_type_mask (completion_type_mask), + m_entries () +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +CommandObjectRegexCommand::~CommandObjectRegexCommand() +{ +} + + +bool +CommandObjectRegexCommand::DoExecute +( + const char *command, + CommandReturnObject &result +) +{ + if (command) + { + EntryCollection::const_iterator pos, end = m_entries.end(); + for (pos = m_entries.begin(); pos != end; ++pos) + { + RegularExpression::Match regex_match(m_max_matches); + + if (pos->regex.Execute (command, ®ex_match)) + { + std::string new_command(pos->command); + std::string match_str; + char percent_var[8]; + size_t idx, percent_var_idx; + for (uint32_t match_idx=1; match_idx <= m_max_matches; ++match_idx) + { + if (regex_match.GetMatchAtIndex (command, match_idx, match_str)) + { + const int percent_var_len = ::snprintf (percent_var, sizeof(percent_var), "%%%u", match_idx); + for (idx = 0; (percent_var_idx = new_command.find(percent_var, idx)) != std::string::npos; ) + { + new_command.erase(percent_var_idx, percent_var_len); + new_command.insert(percent_var_idx, match_str); + idx += percent_var_idx + match_str.size(); + } + } + } + // Interpret the new command and return this as the result! + if (m_interpreter.GetExpandRegexAliases()) + result.GetOutputStream().Printf("%s\n", new_command.c_str()); + // Pass in true for "no context switching". The command that called us should have set up the context + // appropriately, we shouldn't have to redo that. + return m_interpreter.HandleCommand(new_command.c_str(), eLazyBoolCalculate, result, NULL, true, true); + } + } + result.SetStatus(eReturnStatusFailed); + if (GetSyntax() != NULL) + result.AppendError (GetSyntax()); + else + result.AppendErrorWithFormat ("Command contents '%s' failed to match any regular expression in the '%s' regex command.\n", + command, + m_cmd_name.c_str()); + return false; + } + result.AppendError("empty command passed to regular expression command"); + result.SetStatus(eReturnStatusFailed); + return false; +} + + +bool +CommandObjectRegexCommand::AddRegexCommand (const char *re_cstr, const char *command_cstr) +{ + m_entries.resize(m_entries.size() + 1); + // Only add the regular expression if it compiles + if (m_entries.back().regex.Compile (re_cstr, REG_EXTENDED)) + { + m_entries.back().command.assign (command_cstr); + return true; + } + // The regex didn't compile... + m_entries.pop_back(); + return false; +} + +int +CommandObjectRegexCommand::HandleCompletion (Args &input, + int &cursor_index, + int &cursor_char_position, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches) +{ + if (m_completion_type_mask) + { + std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position); + CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter, + m_completion_type_mask, + completion_str.c_str(), + match_start_point, + max_return_elements, + NULL, + word_complete, + matches); + return matches.GetSize(); + } + else + { + matches.Clear(); + word_complete = false; + } + return 0; +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandObjectScript.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandObjectScript.cpp new file mode 100644 index 0000000..aff507d --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandObjectScript.cpp @@ -0,0 +1,93 @@ +//===-- CommandObjectScript.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/lldb-python.h" + +#include "CommandObjectScript.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes + +#include "lldb/Core/Debugger.h" + +#include "lldb/DataFormatters/DataVisualization.h" + +#include "lldb/Interpreter/Args.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/ScriptInterpreter.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectScript +//------------------------------------------------------------------------- + +CommandObjectScript::CommandObjectScript (CommandInterpreter &interpreter, ScriptLanguage script_lang) : + CommandObjectRaw (interpreter, + "script", + "Pass an expression to the script interpreter for evaluation and return the results. Drop into the interactive interpreter if no expression is given.", + "script [<script-expression-for-evaluation>]") +{ +} + +CommandObjectScript::~CommandObjectScript () +{ +} + +bool +CommandObjectScript::DoExecute +( + const char *command, + CommandReturnObject &result +) +{ +#ifdef LLDB_DISABLE_PYTHON + // if we ever support languages other than Python this simple #ifdef won't work + result.AppendError("your copy of LLDB does not support scripting."); + result.SetStatus (eReturnStatusFailed); + return false; +#else + if (m_interpreter.GetDebugger().GetScriptLanguage() == lldb::eScriptLanguageNone) + { + result.AppendError("the script-lang setting is set to none - scripting not available"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + ScriptInterpreter *script_interpreter = m_interpreter.GetScriptInterpreter (); + + if (script_interpreter == NULL) + { + result.AppendError("no script interpreter"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + DataVisualization::ForceUpdate(); // script might change Python code we use for formatting.. make sure we keep up to date with it + + if (command == NULL || command[0] == '\0') + { + script_interpreter->ExecuteInterpreterLoop (); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + return result.Succeeded(); + } + + // We can do better when reporting the status of one-liner script execution. + if (script_interpreter->ExecuteOneLine (command, &result)) + result.SetStatus(eReturnStatusSuccessFinishNoResult); + else + result.SetStatus(eReturnStatusFailed); + + return result.Succeeded(); +#endif +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandObjectScript.h b/contrib/llvm/tools/lldb/source/Interpreter/CommandObjectScript.h new file mode 100644 index 0000000..fd55fc4 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandObjectScript.h @@ -0,0 +1,42 @@ +//===-- CommandObjectScript.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_CommandObjectScript_h_ +#define liblldb_CommandObjectScript_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectScript +//------------------------------------------------------------------------- + +class CommandObjectScript : public CommandObjectRaw +{ +public: + + CommandObjectScript (CommandInterpreter &interpreter, + lldb::ScriptLanguage script_lang); + + virtual + ~CommandObjectScript (); + +protected: + virtual bool + DoExecute (const char *command, CommandReturnObject &result); +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectScript_h_ diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandReturnObject.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandReturnObject.cpp new file mode 100644 index 0000000..9c63753 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandReturnObject.cpp @@ -0,0 +1,219 @@ +//===-- CommandReturnObject.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/CommandReturnObject.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Error.h" +#include "lldb/Core/StreamString.h" + +using namespace lldb; +using namespace lldb_private; + +static void +DumpStringToStreamWithNewline (Stream &strm, const std::string &s, bool add_newline_if_empty) +{ + bool add_newline = false; + if (s.empty()) + { + add_newline = add_newline_if_empty; + } + else + { + // We already checked for empty above, now make sure there is a newline + // in the error, and if there isn't one, add one. + strm.Write(s.c_str(), s.size()); + + const char last_char = *s.rbegin(); + add_newline = last_char != '\n' && last_char != '\r'; + + } + if (add_newline) + strm.EOL(); +} + + +CommandReturnObject::CommandReturnObject () : + m_out_stream (), + m_err_stream (), + m_status (eReturnStatusStarted), + m_did_change_process_state (false) +{ +} + +CommandReturnObject::~CommandReturnObject () +{ +} + +void +CommandReturnObject::AppendErrorWithFormat (const char *format, ...) +{ + if (!format) + return; + va_list args; + va_start (args, format); + StreamString sstrm; + sstrm.PrintfVarArg(format, args); + va_end (args); + + + const std::string &s = sstrm.GetString(); + if (!s.empty()) + { + Stream &error_strm = GetErrorStream(); + error_strm.PutCString ("error: "); + DumpStringToStreamWithNewline (error_strm, s, false); + } +} + +void +CommandReturnObject::AppendMessageWithFormat (const char *format, ...) +{ + if (!format) + return; + va_list args; + va_start (args, format); + StreamString sstrm; + sstrm.PrintfVarArg(format, args); + va_end (args); + + GetOutputStream().Printf("%s", sstrm.GetData()); +} + +void +CommandReturnObject::AppendWarningWithFormat (const char *format, ...) +{ + if (!format) + return; + va_list args; + va_start (args, format); + StreamString sstrm; + sstrm.PrintfVarArg(format, args); + va_end (args); + + GetErrorStream().Printf("warning: %s", sstrm.GetData()); +} + +void +CommandReturnObject::AppendMessage (const char *in_string) +{ + if (!in_string) + return; + GetOutputStream().Printf("%s\n", in_string); +} + +void +CommandReturnObject::AppendWarning (const char *in_string) +{ + if (!in_string || *in_string == '\0') + return; + GetErrorStream().Printf("warning: %s\n", in_string); +} + +// Similar to AppendWarning, but do not prepend 'warning: ' to message, and +// don't append "\n" to the end of it. + +void +CommandReturnObject::AppendRawWarning (const char *in_string) +{ + if (in_string && in_string[0]) + GetErrorStream().PutCString(in_string); +} + +void +CommandReturnObject::AppendError (const char *in_string) +{ + if (!in_string || *in_string == '\0') + return; + GetErrorStream().Printf ("error: %s\n", in_string); +} + +void +CommandReturnObject::SetError (const Error &error, const char *fallback_error_cstr) +{ + const char *error_cstr = error.AsCString(); + if (error_cstr == NULL) + error_cstr = fallback_error_cstr; + SetError(error_cstr); +} + +void +CommandReturnObject::SetError (const char *error_cstr) +{ + if (error_cstr) + { + AppendError (error_cstr); + SetStatus (eReturnStatusFailed); + } +} + +// Similar to AppendError, but do not prepend 'Error: ' to message, and +// don't append "\n" to the end of it. + +void +CommandReturnObject::AppendRawError (const char *in_string) +{ + if (in_string && in_string[0]) + GetErrorStream().PutCString(in_string); +} + +void +CommandReturnObject::SetStatus (ReturnStatus status) +{ + m_status = status; +} + +ReturnStatus +CommandReturnObject::GetStatus () +{ + return m_status; +} + +bool +CommandReturnObject::Succeeded () +{ + return m_status <= eReturnStatusSuccessContinuingResult; +} + +bool +CommandReturnObject::HasResult () +{ + return (m_status == eReturnStatusSuccessFinishResult || + m_status == eReturnStatusSuccessContinuingResult); +} + +void +CommandReturnObject::Clear() +{ + lldb::StreamSP stream_sp; + stream_sp = m_out_stream.GetStreamAtIndex (eStreamStringIndex); + if (stream_sp) + static_cast<StreamString *>(stream_sp.get())->Clear(); + stream_sp = m_err_stream.GetStreamAtIndex (eStreamStringIndex); + if (stream_sp) + static_cast<StreamString *>(stream_sp.get())->Clear(); + m_status = eReturnStatusStarted; + m_did_change_process_state = false; +} + +bool +CommandReturnObject::GetDidChangeProcessState () +{ + return m_did_change_process_state; +} + +void +CommandReturnObject::SetDidChangeProcessState (bool b) +{ + m_did_change_process_state = b; +} + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupArchitecture.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupArchitecture.cpp new file mode 100644 index 0000000..af103bb --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupArchitecture.cpp @@ -0,0 +1,86 @@ +//===-- OptionGroupArchitecture.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/OptionGroupArchitecture.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Utility/Utils.h" + +using namespace lldb; +using namespace lldb_private; + +OptionGroupArchitecture::OptionGroupArchitecture() : + m_arch_str () +{ +} + +OptionGroupArchitecture::~OptionGroupArchitecture () +{ +} + +static OptionDefinition +g_option_table[] = +{ + { LLDB_OPT_SET_1 , false, "arch" , 'a', required_argument, NULL, 0, eArgTypeArchitecture , "Specify the architecture for the target."}, +}; + +uint32_t +OptionGroupArchitecture::GetNumDefinitions () +{ + return llvm::array_lengthof(g_option_table); +} + +const OptionDefinition * +OptionGroupArchitecture::GetDefinitions () +{ + return g_option_table; +} + +bool +OptionGroupArchitecture::GetArchitecture (Platform *platform, ArchSpec &arch) +{ + if (m_arch_str.empty()) + arch.Clear(); + else + arch.SetTriple(m_arch_str.c_str(), platform); + return arch.IsValid(); +} + + +Error +OptionGroupArchitecture::SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_arg) +{ + Error error; + const int short_option = g_option_table[option_idx].short_option; + + switch (short_option) + { + case 'a': + m_arch_str.assign (option_arg); + break; + + default: + error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); + break; + } + + return error; +} + +void +OptionGroupArchitecture::OptionParsingStarting (CommandInterpreter &interpreter) +{ + m_arch_str.clear(); +} + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupBoolean.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupBoolean.cpp new file mode 100644 index 0000000..5b5b384 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupBoolean.cpp @@ -0,0 +1,67 @@ +//===-- OptionGroupBoolean.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/OptionGroupBoolean.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes + +using namespace lldb; +using namespace lldb_private; + +OptionGroupBoolean::OptionGroupBoolean (uint32_t usage_mask, + bool required, + const char *long_option, + int short_option, + const char *usage_text, + bool default_value, + bool no_argument_toggle_default) : + m_value (default_value, default_value) +{ + m_option_definition.usage_mask = usage_mask; + m_option_definition.required = required; + m_option_definition.long_option = long_option; + m_option_definition.short_option = short_option; + m_option_definition.option_has_arg = no_argument_toggle_default ? no_argument : required_argument; + m_option_definition.enum_values = NULL; + m_option_definition.completion_type = 0; + m_option_definition.argument_type = eArgTypeBoolean; + m_option_definition.usage_text = usage_text; +} + +OptionGroupBoolean::~OptionGroupBoolean () +{ +} + +Error +OptionGroupBoolean::SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_arg) +{ + Error error; + if (m_option_definition.option_has_arg == no_argument) + { + // Not argument, toggle the default value and mark the option as having been set + m_value.SetCurrentValue (!m_value.GetDefaultValue()); + m_value.SetOptionWasSet (); + } + else + { + error = m_value.SetValueFromCString (option_arg); + } + return error; +} + +void +OptionGroupBoolean::OptionParsingStarting (CommandInterpreter &interpreter) +{ + m_value.Clear(); +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFile.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFile.cpp new file mode 100644 index 0000000..6867395 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFile.cpp @@ -0,0 +1,97 @@ +//===-- OptionGroupFile.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/OptionGroupFile.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes + +using namespace lldb; +using namespace lldb_private; + +OptionGroupFile::OptionGroupFile (uint32_t usage_mask, + bool required, + const char *long_option, + int short_option, + uint32_t completion_type, + lldb::CommandArgumentType argument_type, + const char *usage_text) : + m_file () +{ + m_option_definition.usage_mask = usage_mask; + m_option_definition.required = required; + m_option_definition.long_option = long_option; + m_option_definition.short_option = short_option; + m_option_definition.option_has_arg = required_argument; + m_option_definition.enum_values = NULL; + m_option_definition.completion_type = completion_type; + m_option_definition.argument_type = argument_type; + m_option_definition.usage_text = usage_text; +} + +OptionGroupFile::~OptionGroupFile () +{ +} + +Error +OptionGroupFile::SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_arg) +{ + Error error (m_file.SetValueFromCString (option_arg)); + return error; +} + +void +OptionGroupFile::OptionParsingStarting (CommandInterpreter &interpreter) +{ + m_file.Clear(); +} + + +OptionGroupFileList::OptionGroupFileList (uint32_t usage_mask, + bool required, + const char *long_option, + int short_option, + uint32_t completion_type, + lldb::CommandArgumentType argument_type, + const char *usage_text) : + m_file_list () +{ + m_option_definition.usage_mask = usage_mask; + m_option_definition.required = required; + m_option_definition.long_option = long_option; + m_option_definition.short_option = short_option; + m_option_definition.option_has_arg = required_argument; + m_option_definition.enum_values = NULL; + m_option_definition.completion_type = completion_type; + m_option_definition.argument_type = argument_type; + m_option_definition.usage_text = usage_text; +} + +OptionGroupFileList::~OptionGroupFileList () +{ +} + +Error +OptionGroupFileList::SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_arg) +{ + Error error (m_file_list.SetValueFromCString (option_arg)); + return error; +} + +void +OptionGroupFileList::OptionParsingStarting (CommandInterpreter &interpreter) +{ + m_file_list.Clear(); +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFormat.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFormat.cpp new file mode 100644 index 0000000..790cbb6 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFormat.cpp @@ -0,0 +1,249 @@ +//===-- OptionGroupFormat.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/lldb-python.h" + +#include "lldb/Interpreter/OptionGroupFormat.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/ArchSpec.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/Utils.h" + +using namespace lldb; +using namespace lldb_private; + +OptionGroupFormat::OptionGroupFormat (lldb::Format default_format, + uint64_t default_byte_size, + uint64_t default_count) : + m_format (default_format, default_format), + m_byte_size (default_byte_size, default_byte_size), + m_count (default_count, default_count), + m_prev_gdb_format('x'), + m_prev_gdb_size('w') +{ +} + +OptionGroupFormat::~OptionGroupFormat () +{ +} + +static OptionDefinition +g_option_table[] = +{ +{ LLDB_OPT_SET_1, false, "format" ,'f', required_argument, NULL, 0, eArgTypeFormat , "Specify a format to be used for display."}, +{ LLDB_OPT_SET_2, false, "gdb-format",'G', required_argument, NULL, 0, eArgTypeGDBFormat, "Specify a format using a GDB format specifier string."}, +{ LLDB_OPT_SET_3, false, "size" ,'s', required_argument, NULL, 0, eArgTypeByteSize , "The size in bytes to use when displaying with the selected format."}, +{ LLDB_OPT_SET_4, false, "count" ,'c', required_argument, NULL, 0, eArgTypeCount , "The number of total items to display."}, +}; + +uint32_t +OptionGroupFormat::GetNumDefinitions () +{ + if (m_byte_size.GetDefaultValue() < UINT64_MAX) + { + if (m_count.GetDefaultValue() < UINT64_MAX) + return 4; + else + return 3; + } + return 2; +} + +const OptionDefinition * +OptionGroupFormat::GetDefinitions () +{ + return g_option_table; +} + +Error +OptionGroupFormat::SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_arg) +{ + Error error; + const int short_option = g_option_table[option_idx].short_option; + + switch (short_option) + { + case 'f': + error = m_format.SetValueFromCString (option_arg); + break; + + case 'c': + if (m_count.GetDefaultValue() == 0) + { + error.SetErrorString ("--count option is disabled"); + } + else + { + error = m_count.SetValueFromCString (option_arg); + if (m_count.GetCurrentValue() == 0) + error.SetErrorStringWithFormat("invalid --count option value '%s'", option_arg); + } + break; + + case 's': + if (m_byte_size.GetDefaultValue() == 0) + { + error.SetErrorString ("--size option is disabled"); + } + else + { + error = m_byte_size.SetValueFromCString (option_arg); + if (m_byte_size.GetCurrentValue() == 0) + error.SetErrorStringWithFormat("invalid --size option value '%s'", option_arg); + } + break; + + case 'G': + { + char *end = NULL; + const char *gdb_format_cstr = option_arg; + uint64_t count = 0; + if (::isdigit (gdb_format_cstr[0])) + { + count = strtoull (gdb_format_cstr, &end, 0); + + if (option_arg != end) + gdb_format_cstr = end; // We have a valid count, advance the string position + else + count = 0; + } + + Format format = eFormatDefault; + uint32_t byte_size = 0; + + while (ParserGDBFormatLetter (interpreter, gdb_format_cstr[0], format, byte_size)) + { + ++gdb_format_cstr; + } + + // We the first character of the "gdb_format_cstr" is not the + // NULL terminator, we didn't consume the entire string and + // something is wrong. Also, if none of the format, size or count + // was specified correctly, then abort. + if (gdb_format_cstr[0] || (format == eFormatInvalid && byte_size == 0 && count == 0)) + { + // Nothing got set correctly + error.SetErrorStringWithFormat ("invalid gdb format string '%s'", option_arg); + return error; + } + + // At least one of the format, size or count was set correctly. + // Anything that wasn't set correctly should be set to the + // previous default + if (format == eFormatInvalid) + ParserGDBFormatLetter (interpreter, m_prev_gdb_format, format, byte_size); + + const bool byte_size_enabled = m_byte_size.GetDefaultValue() < UINT64_MAX; + const bool count_enabled = m_count.GetDefaultValue() < UINT64_MAX; + if (byte_size_enabled) + { + // Byte size is enabled + if (byte_size == 0) + ParserGDBFormatLetter (interpreter, m_prev_gdb_size, format, byte_size); + } + else + { + // Byte size is disabled, make sure it wasn't specified + if (byte_size > 0) + { + error.SetErrorString ("this command doesn't support specifying a byte size"); + return error; + } + } + + if (count_enabled) + { + // Count is enabled and was not set, set it to the default for gdb format statements (which is 1). + if (count == 0) + count = 1; + } + else + { + // Count is disabled, make sure it wasn't specified + if (count > 0) + { + error.SetErrorString ("this command doesn't support specifying a count"); + return error; + } + } + + m_format.SetCurrentValue (format); + m_format.SetOptionWasSet (); + if (byte_size_enabled) + { + m_byte_size.SetCurrentValue (byte_size); + m_byte_size.SetOptionWasSet (); + } + if (count_enabled) + { + m_count.SetCurrentValue(count); + m_count.SetOptionWasSet (); + } + } + break; + + default: + error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); + break; + } + + return error; +} + +bool +OptionGroupFormat::ParserGDBFormatLetter (CommandInterpreter &interpreter, char format_letter, Format &format, uint32_t &byte_size) +{ + m_has_gdb_format = true; + switch (format_letter) + { + case 'o': format = eFormatOctal; m_prev_gdb_format = format_letter; return true; + case 'x': format = eFormatHex; m_prev_gdb_format = format_letter; return true; + case 'd': format = eFormatDecimal; m_prev_gdb_format = format_letter; return true; + case 'u': format = eFormatUnsigned; m_prev_gdb_format = format_letter; return true; + case 't': format = eFormatBinary; m_prev_gdb_format = format_letter; return true; + case 'f': format = eFormatFloat; m_prev_gdb_format = format_letter; return true; + case 'a': format = eFormatAddressInfo; + { + ExecutionContext exe_ctx(interpreter.GetExecutionContext()); + Target *target = exe_ctx.GetTargetPtr(); + if (target) + byte_size = target->GetArchitecture().GetAddressByteSize(); + m_prev_gdb_format = format_letter; + return true; + } + case 'i': format = eFormatInstruction; m_prev_gdb_format = format_letter; return true; + case 'c': format = eFormatChar; m_prev_gdb_format = format_letter; return true; + case 's': format = eFormatCString; m_prev_gdb_format = format_letter; return true; + case 'T': format = eFormatOSType; m_prev_gdb_format = format_letter; return true; + case 'A': format = eFormatHexFloat; m_prev_gdb_format = format_letter; return true; + case 'b': byte_size = 1; m_prev_gdb_size = format_letter; return true; + case 'h': byte_size = 2; m_prev_gdb_size = format_letter; return true; + case 'w': byte_size = 4; m_prev_gdb_size = format_letter; return true; + case 'g': byte_size = 8; m_prev_gdb_size = format_letter; return true; + default: break; + } + return false; +} + +void +OptionGroupFormat::OptionParsingStarting (CommandInterpreter &interpreter) +{ + m_format.Clear(); + m_byte_size.Clear(); + m_count.Clear(); + m_has_gdb_format = false; +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupOutputFile.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupOutputFile.cpp new file mode 100644 index 0000000..aa01bf5 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupOutputFile.cpp @@ -0,0 +1,81 @@ +//===-- OptionGroupOutputFile.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/OptionGroupOutputFile.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Utility/Utils.h" + +using namespace lldb; +using namespace lldb_private; + +OptionGroupOutputFile::OptionGroupOutputFile() : + m_file (), + m_append (false, false) +{ +} + +OptionGroupOutputFile::~OptionGroupOutputFile () +{ +} + +static OptionDefinition +g_option_table[] = +{ + { LLDB_OPT_SET_1 , false, "outfile", 'o', required_argument, NULL, 0, eArgTypeFilename , "Specify a path for capturing command output."}, + { LLDB_OPT_SET_1 , false, "append-outfile" , 'apnd', no_argument, NULL, 0, eArgTypeNone , "Append to the the file specified with '--outfile <path>'."}, +}; + +uint32_t +OptionGroupOutputFile::GetNumDefinitions () +{ + return llvm::array_lengthof(g_option_table); +} + +const OptionDefinition * +OptionGroupOutputFile::GetDefinitions () +{ + return g_option_table; +} + +Error +OptionGroupOutputFile::SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_arg) +{ + Error error; + const int short_option = g_option_table[option_idx].short_option; + + switch (short_option) + { + case 'o': + error = m_file.SetValueFromCString (option_arg); + break; + + case 'apnd': + m_append.SetCurrentValue(true); + break; + + default: + error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); + break; + } + + return error; +} + +void +OptionGroupOutputFile::OptionParsingStarting (CommandInterpreter &interpreter) +{ + m_file.Clear(); + m_append.Clear(); +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupPlatform.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupPlatform.cpp new file mode 100644 index 0000000..a54edaf --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupPlatform.cpp @@ -0,0 +1,149 @@ +//===-- OptionGroupPlatform.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/lldb-python.h" + +#include "lldb/Interpreter/OptionGroupPlatform.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Target/Platform.h" +#include "lldb/Utility/Utils.h" + +using namespace lldb; +using namespace lldb_private; + +PlatformSP +OptionGroupPlatform::CreatePlatformWithOptions (CommandInterpreter &interpreter, + const ArchSpec &arch, + bool make_selected, + Error& error, + ArchSpec &platform_arch) const +{ + PlatformSP platform_sp; + + if (!m_platform_name.empty()) + { + platform_sp = Platform::Create (m_platform_name.c_str(), error); + if (platform_sp) + { + if (platform_arch.IsValid() && !platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch)) + { + error.SetErrorStringWithFormat ("platform '%s' doesn't support '%s'", + platform_sp->GetName().GetCString(), + arch.GetTriple().getTriple().c_str()); + platform_sp.reset(); + return platform_sp; + } + } + } + else if (arch.IsValid()) + { + platform_sp = Platform::Create (arch, &platform_arch, error); + } + + if (platform_sp) + { + interpreter.GetDebugger().GetPlatformList().Append (platform_sp, make_selected); + if (m_os_version_major != UINT32_MAX) + { + platform_sp->SetOSVersion (m_os_version_major, + m_os_version_minor, + m_os_version_update); + } + + if (m_sdk_sysroot) + platform_sp->SetSDKRootDirectory (m_sdk_sysroot); + + if (m_sdk_build) + platform_sp->SetSDKBuild (m_sdk_build); + } + + return platform_sp; +} + +void +OptionGroupPlatform::OptionParsingStarting (CommandInterpreter &interpreter) +{ + m_platform_name.clear(); + m_sdk_sysroot.Clear(); + m_sdk_build.Clear(); + m_os_version_major = UINT32_MAX; + m_os_version_minor = UINT32_MAX; + m_os_version_update = UINT32_MAX; +} + +static OptionDefinition +g_option_table[] = +{ + { LLDB_OPT_SET_ALL, false, "platform", 'p', required_argument, NULL, 0, eArgTypePlatform, "Specify name of the platform to use for this target, creating the platform if necessary."}, + { LLDB_OPT_SET_ALL, false, "version" , 'v', required_argument, NULL, 0, eArgTypeNone, "Specify the initial SDK version to use prior to connecting." }, + { LLDB_OPT_SET_ALL, false, "build" , 'b', required_argument, NULL, 0, eArgTypeNone, "Specify the initial SDK build number." }, + { LLDB_OPT_SET_ALL, false, "sysroot" , 'S', required_argument, NULL, 0, eArgTypeFilename, "Specify the SDK root directory that contains a root of all remote system files." } +}; + +const OptionDefinition* +OptionGroupPlatform::GetDefinitions () +{ + if (m_include_platform_option) + return g_option_table; + return g_option_table + 1; +} + +uint32_t +OptionGroupPlatform::GetNumDefinitions () +{ + if (m_include_platform_option) + return llvm::array_lengthof(g_option_table); + return llvm::array_lengthof(g_option_table) - 1; +} + + +Error +OptionGroupPlatform::SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_arg) +{ + Error error; + if (!m_include_platform_option) + ++option_idx; + + const int short_option = g_option_table[option_idx].short_option; + + switch (short_option) + { + case 'p': + m_platform_name.assign (option_arg); + break; + + case 'v': + if (Args::StringToVersion (option_arg, + m_os_version_major, + m_os_version_minor, + m_os_version_update) == option_arg) + error.SetErrorStringWithFormat ("invalid version string '%s'", option_arg); + break; + + case 'b': + m_sdk_build.SetCString (option_arg); + break; + + case 'S': + m_sdk_sysroot.SetCString (option_arg); + break; + + default: + error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); + break; + } + return error; +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupString.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupString.cpp new file mode 100644 index 0000000..ee96239 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupString.cpp @@ -0,0 +1,58 @@ +//===-- OptionGroupString.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/OptionGroupString.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes + +using namespace lldb; +using namespace lldb_private; + +OptionGroupString::OptionGroupString (uint32_t usage_mask, + bool required, + const char *long_option, + int short_option, + uint32_t completion_type, + lldb::CommandArgumentType argument_type, + const char *usage_text, + const char *default_value) : + m_value (default_value, default_value) +{ + m_option_definition.usage_mask = usage_mask; + m_option_definition.required = required; + m_option_definition.long_option = long_option; + m_option_definition.short_option = short_option; + m_option_definition.option_has_arg = required_argument; + m_option_definition.enum_values = NULL; + m_option_definition.completion_type = completion_type; + m_option_definition.argument_type = argument_type; + m_option_definition.usage_text = usage_text; +} + +OptionGroupString::~OptionGroupString () +{ +} + +Error +OptionGroupString::SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_arg) +{ + Error error (m_value.SetValueFromCString (option_arg)); + return error; +} + +void +OptionGroupString::OptionParsingStarting (CommandInterpreter &interpreter) +{ + m_value.Clear(); +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUInt64.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUInt64.cpp new file mode 100644 index 0000000..e6996f7 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUInt64.cpp @@ -0,0 +1,58 @@ +//===-- OptionGroupUInt64.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/OptionGroupUInt64.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes + +using namespace lldb; +using namespace lldb_private; + +OptionGroupUInt64::OptionGroupUInt64 (uint32_t usage_mask, + bool required, + const char *long_option, + int short_option, + uint32_t completion_type, + lldb::CommandArgumentType argument_type, + const char *usage_text, + uint64_t default_value) : + m_value (default_value, default_value) +{ + m_option_definition.usage_mask = usage_mask; + m_option_definition.required = required; + m_option_definition.long_option = long_option; + m_option_definition.short_option = short_option; + m_option_definition.option_has_arg = required_argument; + m_option_definition.enum_values = NULL; + m_option_definition.completion_type = completion_type; + m_option_definition.argument_type = argument_type; + m_option_definition.usage_text = usage_text; +} + +OptionGroupUInt64::~OptionGroupUInt64 () +{ +} + +Error +OptionGroupUInt64::SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_arg) +{ + Error error (m_value.SetValueFromCString (option_arg)); + return error; +} + +void +OptionGroupUInt64::OptionParsingStarting (CommandInterpreter &interpreter) +{ + m_value.Clear(); +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUUID.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUUID.cpp new file mode 100644 index 0000000..14bdc84 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUUID.cpp @@ -0,0 +1,76 @@ +//===-- OptionGroupUUID.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/OptionGroupUUID.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Utility/Utils.h" + +using namespace lldb; +using namespace lldb_private; + +OptionGroupUUID::OptionGroupUUID() : + m_uuid () +{ +} + +OptionGroupUUID::~OptionGroupUUID () +{ +} + +static OptionDefinition +g_option_table[] = +{ + { LLDB_OPT_SET_1 , false, "uuid", 'u', required_argument, NULL, 0, eArgTypeNone, "A module UUID value."}, +}; + +uint32_t +OptionGroupUUID::GetNumDefinitions () +{ + return llvm::array_lengthof(g_option_table); +} + +const OptionDefinition * +OptionGroupUUID::GetDefinitions () +{ + return g_option_table; +} + +Error +OptionGroupUUID::SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_arg) +{ + Error error; + const int short_option = g_option_table[option_idx].short_option; + + switch (short_option) + { + case 'u': + error = m_uuid.SetValueFromCString (option_arg); + if (error.Success()) + m_uuid.SetOptionWasSet(); + break; + + default: + error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); + break; + } + + return error; +} + +void +OptionGroupUUID::OptionParsingStarting (CommandInterpreter &interpreter) +{ + m_uuid.Clear(); +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp new file mode 100644 index 0000000..22a7f37 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp @@ -0,0 +1,181 @@ +//===-- OptionGroupValueObjectDisplay.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/lldb-python.h" + +#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Target/Target.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Utility/Utils.h" + +using namespace lldb; +using namespace lldb_private; + +OptionGroupValueObjectDisplay::OptionGroupValueObjectDisplay() +{ +} + +OptionGroupValueObjectDisplay::~OptionGroupValueObjectDisplay () +{ +} + +static OptionDefinition +g_option_table[] = +{ + { LLDB_OPT_SET_1, false, "dynamic-type", 'd', required_argument, g_dynamic_value_types, 0, eArgTypeNone, "Show the object as its full dynamic type, not its static type, if available."}, + { LLDB_OPT_SET_1, false, "synthetic-type", 'S', required_argument, NULL, 0, eArgTypeBoolean, "Show the object obeying its synthetic provider, if available."}, + { LLDB_OPT_SET_1, false, "depth", 'D', required_argument, NULL, 0, eArgTypeCount, "Set the max recurse depth when dumping aggregate types (default is infinity)."}, + { LLDB_OPT_SET_1, false, "flat", 'F', no_argument, NULL, 0, eArgTypeNone, "Display results in a flat format that uses expression paths for each variable or member."}, + { LLDB_OPT_SET_1, false, "location", 'L', no_argument, NULL, 0, eArgTypeNone, "Show variable location information."}, + { LLDB_OPT_SET_1, false, "object-description", 'O', no_argument, NULL, 0, eArgTypeNone, "Print as an Objective-C object."}, + { LLDB_OPT_SET_1, false, "ptr-depth", 'P', required_argument, NULL, 0, eArgTypeCount, "The number of pointers to be traversed when dumping values (default is zero)."}, + { LLDB_OPT_SET_1, false, "show-types", 'T', no_argument, NULL, 0, eArgTypeNone, "Show variable types when dumping values."}, + { LLDB_OPT_SET_1, false, "no-summary-depth", 'Y', optional_argument, NULL, 0, eArgTypeCount, "Set the depth at which omitting summary information stops (default is 1)."}, + { LLDB_OPT_SET_1, false, "raw-output", 'R', no_argument, NULL, 0, eArgTypeNone, "Don't use formatting options."}, + { LLDB_OPT_SET_1, false, "show-all-children", 'A', no_argument, NULL, 0, eArgTypeNone, "Ignore the upper bound on the number of children to show."}, + { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } +}; + +uint32_t +OptionGroupValueObjectDisplay::GetNumDefinitions () +{ + return llvm::array_lengthof(g_option_table); +} + +const OptionDefinition * +OptionGroupValueObjectDisplay::GetDefinitions () +{ + return g_option_table; +} + + +Error +OptionGroupValueObjectDisplay::SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_arg) +{ + Error error; + const int short_option = g_option_table[option_idx].short_option; + bool success = false; + + switch (short_option) + { + case 'd': + { + int32_t result; + result = Args::StringToOptionEnum (option_arg, g_dynamic_value_types, 2, error); + if (error.Success()) + use_dynamic = (lldb::DynamicValueType) result; + } + break; + case 'T': show_types = true; break; + case 'L': show_location= true; break; + case 'F': flat_output = true; break; + case 'O': use_objc = true; break; + case 'R': be_raw = true; break; + case 'A': ignore_cap = true; break; + + case 'D': + max_depth = Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success); + if (!success) + error.SetErrorStringWithFormat("invalid max depth '%s'", option_arg); + break; + + case 'P': + ptr_depth = Args::StringToUInt32 (option_arg, 0, 0, &success); + if (!success) + error.SetErrorStringWithFormat("invalid pointer depth '%s'", option_arg); + break; + + case 'Y': + if (option_arg) + { + no_summary_depth = Args::StringToUInt32 (option_arg, 0, 0, &success); + if (!success) + error.SetErrorStringWithFormat("invalid pointer depth '%s'", option_arg); + } + else + no_summary_depth = 1; + break; + + case 'S': + use_synth = Args::StringToBoolean(option_arg, true, &success); + if (!success) + error.SetErrorStringWithFormat("invalid synthetic-type '%s'", option_arg); + break; + default: + error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); + break; + } + + return error; +} + +void +OptionGroupValueObjectDisplay::OptionParsingStarting (CommandInterpreter &interpreter) +{ + // If these defaults change, be sure to modify AnyOptionWasSet(). + show_types = false; + no_summary_depth = 0; + show_location = false; + flat_output = false; + use_objc = false; + max_depth = UINT32_MAX; + ptr_depth = 0; + use_synth = true; + be_raw = false; + ignore_cap = false; + + Target *target = interpreter.GetExecutionContext().GetTargetPtr(); + if (target != NULL) + use_dynamic = target->GetPreferDynamicValue(); + else + { + // If we don't have any targets, then dynamic values won't do us much good. + use_dynamic = lldb::eNoDynamicValues; + } +} + +ValueObject::DumpValueObjectOptions +OptionGroupValueObjectDisplay::GetAsDumpOptions (bool objc_is_compact, + lldb::Format format, + lldb::TypeSummaryImplSP summary_sp) +{ + ValueObject::DumpValueObjectOptions options; + options.SetMaximumPointerDepth(ptr_depth); + if (use_objc) + options.SetShowSummary(false); + else + options.SetOmitSummaryDepth(no_summary_depth); + options.SetMaximumDepth(max_depth) + .SetShowTypes(show_types) + .SetShowLocation(show_location) + .SetUseObjectiveC(use_objc) + .SetUseDynamicType(use_dynamic) + .SetUseSyntheticValue(use_synth) + .SetFlatOutput(flat_output) + .SetIgnoreCap(ignore_cap) + .SetFormat(format) + .SetSummary(summary_sp); + + if (objc_is_compact) + options.SetHideRootType(use_objc) + .SetHideName(use_objc) + .SetHideValue(use_objc); + + if (be_raw) + options.SetRawDisplay(true); + + return options; +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupVariable.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupVariable.cpp new file mode 100644 index 0000000..316747e --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupVariable.cpp @@ -0,0 +1,144 @@ +//===-- OptionGroupVariable.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/lldb-python.h" + +#include "lldb/Interpreter/OptionGroupVariable.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Error.h" +#include "lldb/DataFormatters/DataVisualization.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/Utils.h" + +using namespace lldb; +using namespace lldb_private; + +// if you add any options here, remember to update the counters in OptionGroupVariable::GetNumDefinitions() +static OptionDefinition +g_option_table[] = +{ + { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-args", 'a', no_argument, NULL, 0, eArgTypeNone, "Omit function arguments."}, + { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-locals", 'l', no_argument, NULL, 0, eArgTypeNone, "Omit local variables."}, + { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "show-globals", 'g', no_argument, NULL, 0, eArgTypeNone, "Show the current frame source file global and static variables."}, + { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "show-declaration",'c', no_argument, NULL, 0, eArgTypeNone, "Show variable declaration information (source file and line where the variable was declared)."}, + { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "regex", 'r', no_argument, NULL, 0, eArgTypeRegularExpression, "The <variable-name> argument for name lookups are regular expressions."}, + { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "scope", 's', no_argument, NULL, 0, eArgTypeNone, "Show variable scope (argument, local, global, static)."}, + { LLDB_OPT_SET_1, false, "summary", 'y', required_argument, NULL, 0, eArgTypeName, "Specify the summary that the variable output should use."}, + { LLDB_OPT_SET_2, false, "summary-string", 'z', required_argument, NULL, 0, eArgTypeName, "Specify a summary string to use to format the variable output."}, +}; + +static Error +ValidateNamedSummary (const char* str, void*) +{ + if (!str || !str[0]) + return Error("must specify a valid named summary"); + TypeSummaryImplSP summary_sp; + if (DataVisualization::NamedSummaryFormats::GetSummaryFormat(ConstString(str), summary_sp) == false) + return Error("must specify a valid named summary"); + return Error(); +} + +static Error +ValidateSummaryString (const char* str, void*) +{ + if (!str || !str[0]) + return Error("must specify a non-empty summary string"); + return Error(); +} + +OptionGroupVariable::OptionGroupVariable (bool show_frame_options) : + OptionGroup(), + include_frame_options (show_frame_options), + summary(ValidateNamedSummary), + summary_string(ValidateSummaryString) +{ +} + +OptionGroupVariable::~OptionGroupVariable () +{ +} + +Error +OptionGroupVariable::SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_arg) +{ + Error error; + if (!include_frame_options) + option_idx += 3; + const int short_option = g_option_table[option_idx].short_option; + switch (short_option) + { + case 'r': use_regex = true; break; + case 'a': show_args = false; break; + case 'l': show_locals = false; break; + case 'g': show_globals = true; break; + case 'c': show_decl = true; break; + case 's': + show_scope = true; + break; + case 'y': + error = summary.SetCurrentValue(option_arg); + break; + case 'z': + error = summary_string.SetCurrentValue(option_arg); + break; + default: + error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); + break; + } + + return error; +} + +void +OptionGroupVariable::OptionParsingStarting (CommandInterpreter &interpreter) +{ + show_args = true; // Frame option only + show_locals = true; // Frame option only + show_globals = false; // Frame option only + show_decl = false; + use_regex = false; + show_scope = false; + summary.Clear(); + summary_string.Clear(); +} + +#define NUM_FRAME_OPTS 3 + +const OptionDefinition* +OptionGroupVariable::GetDefinitions () +{ + // Show the "--no-args", "--no-locals" and "--show-globals" + // options if we are showing frame specific options + if (include_frame_options) + return g_option_table; + + // Skip the "--no-args", "--no-locals" and "--show-globals" + // options if we are not showing frame specific options (globals only) + return &g_option_table[NUM_FRAME_OPTS]; +} + +uint32_t +OptionGroupVariable::GetNumDefinitions () +{ + // Count the "--no-args", "--no-locals" and "--show-globals" + // options if we are showing frame specific options. + if (include_frame_options) + return llvm::array_lengthof(g_option_table); + else + return llvm::array_lengthof(g_option_table) - NUM_FRAME_OPTS; +} + + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupWatchpoint.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupWatchpoint.cpp new file mode 100644 index 0000000..9eef37a --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupWatchpoint.cpp @@ -0,0 +1,121 @@ +//===-- OptionGroupWatchpoint.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/OptionGroupWatchpoint.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-enumerations.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Utility/Utils.h" + +using namespace lldb; +using namespace lldb_private; + +static OptionEnumValueElement g_watch_type[] = +{ + { OptionGroupWatchpoint::eWatchRead, "read", "Watch for read"}, + { OptionGroupWatchpoint::eWatchWrite, "write", "Watch for write"}, + { OptionGroupWatchpoint::eWatchReadWrite, "read_write", "Watch for read/write"}, + { 0, NULL, NULL } +}; + +static OptionEnumValueElement g_watch_size[] = +{ + { 1, "1", "Watch for byte size of 1"}, + { 2, "2", "Watch for byte size of 2"}, + { 4, "4", "Watch for byte size of 4"}, + { 8, "8", "Watch for byte size of 8"}, + { 0, NULL, NULL } +}; + +static OptionDefinition +g_option_table[] = +{ + { LLDB_OPT_SET_1, false, "watch", 'w', required_argument, g_watch_type, 0, eArgTypeWatchType, "Specify the type of watching to perform."}, + { LLDB_OPT_SET_1, false, "xsize", 'x', required_argument, g_watch_size, 0, eArgTypeByteSize, "Number of bytes to use to watch a region."} +}; + + +bool +OptionGroupWatchpoint::IsWatchSizeSupported(uint32_t watch_size) +{ + for (uint32_t i = 0; i < llvm::array_lengthof(g_watch_size); ++i) + { + if (g_watch_size[i].value == 0) + break; + if (watch_size == g_watch_size[i].value) + return true; + } + return false; +} + +OptionGroupWatchpoint::OptionGroupWatchpoint () : + OptionGroup() +{ +} + +OptionGroupWatchpoint::~OptionGroupWatchpoint () +{ +} + +Error +OptionGroupWatchpoint::SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_arg) +{ + Error error; + const int short_option = g_option_table[option_idx].short_option; + switch (short_option) + { + case 'w': + { + WatchType tmp_watch_type; + tmp_watch_type = (WatchType) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error); + if (error.Success()) + { + watch_type = tmp_watch_type; + watch_type_specified = true; + } + break; + } + case 'x': + watch_size = (uint32_t) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error); + break; + + default: + error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); + break; + } + + return error; +} + +void +OptionGroupWatchpoint::OptionParsingStarting (CommandInterpreter &interpreter) +{ + watch_type_specified = false; + watch_type = eWatchInvalid; + watch_size = 0; +} + + +const OptionDefinition* +OptionGroupWatchpoint::GetDefinitions () +{ + return g_option_table; +} + +uint32_t +OptionGroupWatchpoint::GetNumDefinitions () +{ + return llvm::array_lengthof(g_option_table); +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValue.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValue.cpp new file mode 100644 index 0000000..1f6b03d --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValue.cpp @@ -0,0 +1,633 @@ +//===-- OptionValue.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/OptionValue.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/StringList.h" +#include "lldb/Interpreter/OptionValues.h" + +using namespace lldb; +using namespace lldb_private; + + +//------------------------------------------------------------------------- +// Get this value as a uint64_t value if it is encoded as a boolean, +// uint64_t or int64_t. Other types will cause "fail_value" to be +// returned +//------------------------------------------------------------------------- +uint64_t +OptionValue::GetUInt64Value (uint64_t fail_value, bool *success_ptr) +{ + if (success_ptr) + *success_ptr = true; + switch (GetType()) + { + case OptionValue::eTypeBoolean: return static_cast<OptionValueBoolean *>(this)->GetCurrentValue(); + case OptionValue::eTypeSInt64: return static_cast<OptionValueSInt64 *>(this)->GetCurrentValue(); + case OptionValue::eTypeUInt64: return static_cast<OptionValueUInt64 *>(this)->GetCurrentValue(); + default: + break; + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} + +Error +OptionValue::SetSubValue (const ExecutionContext *exe_ctx, + VarSetOperationType op, + const char *name, + const char *value) +{ + Error error; + error.SetErrorStringWithFormat("SetSubValue is not supported"); + return error; +} + + +OptionValueBoolean * +OptionValue::GetAsBoolean () +{ + if (GetType () == OptionValue::eTypeBoolean) + return static_cast<OptionValueBoolean *>(this); + return NULL; +} + +const OptionValueBoolean * +OptionValue::GetAsBoolean () const +{ + if (GetType () == OptionValue::eTypeBoolean) + return static_cast<const OptionValueBoolean *>(this); + return NULL; +} + + +OptionValueFileSpec * +OptionValue::GetAsFileSpec () +{ + if (GetType () == OptionValue::eTypeFileSpec) + return static_cast<OptionValueFileSpec *>(this); + return NULL; + +} + +const OptionValueFileSpec * +OptionValue::GetAsFileSpec () const +{ + if (GetType () == OptionValue::eTypeFileSpec) + return static_cast<const OptionValueFileSpec *>(this); + return NULL; + +} + +OptionValueFileSpecList * +OptionValue::GetAsFileSpecList () +{ + if (GetType () == OptionValue::eTypeFileSpecList) + return static_cast<OptionValueFileSpecList *>(this); + return NULL; + +} + +const OptionValueFileSpecList * +OptionValue::GetAsFileSpecList () const +{ + if (GetType () == OptionValue::eTypeFileSpecList) + return static_cast<const OptionValueFileSpecList *>(this); + return NULL; + +} + +OptionValueArch * +OptionValue::GetAsArch () +{ + if (GetType () == OptionValue::eTypeArch) + return static_cast<OptionValueArch *>(this); + return NULL; +} + + +const OptionValueArch * +OptionValue::GetAsArch () const +{ + if (GetType () == OptionValue::eTypeArch) + return static_cast<const OptionValueArch *>(this); + return NULL; +} + +OptionValueArray * +OptionValue::GetAsArray () +{ + if (GetType () == OptionValue::eTypeArray) + return static_cast<OptionValueArray *>(this); + return NULL; +} + + +const OptionValueArray * +OptionValue::GetAsArray () const +{ + if (GetType () == OptionValue::eTypeArray) + return static_cast<const OptionValueArray *>(this); + return NULL; +} + +OptionValueArgs * +OptionValue::GetAsArgs () +{ + if (GetType () == OptionValue::eTypeArgs) + return static_cast<OptionValueArgs *>(this); + return NULL; +} + + +const OptionValueArgs * +OptionValue::GetAsArgs () const +{ + if (GetType () == OptionValue::eTypeArgs) + return static_cast<const OptionValueArgs *>(this); + return NULL; +} + +OptionValueDictionary * +OptionValue::GetAsDictionary () +{ + if (GetType () == OptionValue::eTypeDictionary) + return static_cast<OptionValueDictionary *>(this); + return NULL; +} + +const OptionValueDictionary * +OptionValue::GetAsDictionary () const +{ + if (GetType () == OptionValue::eTypeDictionary) + return static_cast<const OptionValueDictionary *>(this); + return NULL; +} + +OptionValueEnumeration * +OptionValue::GetAsEnumeration () +{ + if (GetType () == OptionValue::eTypeEnum) + return static_cast<OptionValueEnumeration *>(this); + return NULL; +} + +const OptionValueEnumeration * +OptionValue::GetAsEnumeration () const +{ + if (GetType () == OptionValue::eTypeEnum) + return static_cast<const OptionValueEnumeration *>(this); + return NULL; +} + +OptionValueFormat * +OptionValue::GetAsFormat () +{ + if (GetType () == OptionValue::eTypeFormat) + return static_cast<OptionValueFormat *>(this); + return NULL; +} + +const OptionValueFormat * +OptionValue::GetAsFormat () const +{ + if (GetType () == OptionValue::eTypeFormat) + return static_cast<const OptionValueFormat *>(this); + return NULL; +} + +OptionValuePathMappings * +OptionValue::GetAsPathMappings () +{ + if (GetType () == OptionValue::eTypePathMap) + return static_cast<OptionValuePathMappings *>(this); + return NULL; +} + +const OptionValuePathMappings * +OptionValue::GetAsPathMappings () const +{ + if (GetType () == OptionValue::eTypePathMap) + return static_cast<const OptionValuePathMappings *>(this); + return NULL; +} + +OptionValueProperties * +OptionValue::GetAsProperties () +{ + if (GetType () == OptionValue::eTypeProperties) + return static_cast<OptionValueProperties *>(this); + return NULL; +} + +const OptionValueProperties * +OptionValue::GetAsProperties () const +{ + if (GetType () == OptionValue::eTypeProperties) + return static_cast<const OptionValueProperties *>(this); + return NULL; +} + +OptionValueRegex * +OptionValue::GetAsRegex () +{ + if (GetType () == OptionValue::eTypeRegex) + return static_cast<OptionValueRegex *>(this); + return NULL; +} + +const OptionValueRegex * +OptionValue::GetAsRegex () const +{ + if (GetType () == OptionValue::eTypeRegex) + return static_cast<const OptionValueRegex *>(this); + return NULL; +} + +OptionValueSInt64 * +OptionValue::GetAsSInt64 () +{ + if (GetType () == OptionValue::eTypeSInt64) + return static_cast<OptionValueSInt64 *>(this); + return NULL; +} + +const OptionValueSInt64 * +OptionValue::GetAsSInt64 () const +{ + if (GetType () == OptionValue::eTypeSInt64) + return static_cast<const OptionValueSInt64 *>(this); + return NULL; +} + +OptionValueString * +OptionValue::GetAsString () +{ + if (GetType () == OptionValue::eTypeString) + return static_cast<OptionValueString *>(this); + return NULL; +} + +const OptionValueString * +OptionValue::GetAsString () const +{ + if (GetType () == OptionValue::eTypeString) + return static_cast<const OptionValueString *>(this); + return NULL; +} + +OptionValueUInt64 * +OptionValue::GetAsUInt64 () +{ + if (GetType () == OptionValue::eTypeUInt64) + return static_cast<OptionValueUInt64 *>(this); + return NULL; +} + +const OptionValueUInt64 * +OptionValue::GetAsUInt64 () const +{ + if (GetType () == OptionValue::eTypeUInt64) + return static_cast<const OptionValueUInt64 *>(this); + return NULL; +} + +OptionValueUUID * +OptionValue::GetAsUUID () +{ + if (GetType () == OptionValue::eTypeUUID) + return static_cast<OptionValueUUID *>(this); + return NULL; + +} + +const OptionValueUUID * +OptionValue::GetAsUUID () const +{ + if (GetType () == OptionValue::eTypeUUID) + return static_cast<const OptionValueUUID *>(this); + return NULL; + +} + +bool +OptionValue::GetBooleanValue (bool fail_value) const +{ + const OptionValueBoolean *option_value = GetAsBoolean (); + if (option_value) + return option_value->GetCurrentValue(); + return fail_value; +} + +bool +OptionValue::SetBooleanValue (bool new_value) +{ + OptionValueBoolean *option_value = GetAsBoolean (); + if (option_value) + { + option_value->SetCurrentValue(new_value); + return true; + } + return false; +} + +int64_t +OptionValue::GetEnumerationValue (int64_t fail_value) const +{ + const OptionValueEnumeration *option_value = GetAsEnumeration(); + if (option_value) + return option_value->GetCurrentValue(); + return fail_value; +} + +bool +OptionValue::SetEnumerationValue (int64_t value) +{ + OptionValueEnumeration *option_value = GetAsEnumeration(); + if (option_value) + { + option_value->SetCurrentValue(value); + return true; + } + return false; +} + +FileSpec +OptionValue::GetFileSpecValue () const +{ + const OptionValueFileSpec *option_value = GetAsFileSpec (); + if (option_value) + return option_value->GetCurrentValue(); + return FileSpec(); +} + + +bool +OptionValue::SetFileSpecValue (const FileSpec &file_spec) +{ + OptionValueFileSpec *option_value = GetAsFileSpec (); + if (option_value) + { + option_value->SetCurrentValue(file_spec, false); + return true; + } + return false; +} + +FileSpecList +OptionValue::GetFileSpecListValue () const +{ + const OptionValueFileSpecList *option_value = GetAsFileSpecList (); + if (option_value) + return option_value->GetCurrentValue(); + return FileSpecList(); +} + + +lldb::Format +OptionValue::GetFormatValue (lldb::Format fail_value) const +{ + const OptionValueFormat *option_value = GetAsFormat (); + if (option_value) + return option_value->GetCurrentValue(); + return fail_value; +} + +bool +OptionValue::SetFormatValue (lldb::Format new_value) +{ + OptionValueFormat *option_value = GetAsFormat (); + if (option_value) + { + option_value->SetCurrentValue(new_value); + return true; + } + return false; +} + +const RegularExpression * +OptionValue::GetRegexValue () const +{ + const OptionValueRegex *option_value = GetAsRegex (); + if (option_value) + return option_value->GetCurrentValue(); + return NULL; +} + + +int64_t +OptionValue::GetSInt64Value (int64_t fail_value) const +{ + const OptionValueSInt64 *option_value = GetAsSInt64 (); + if (option_value) + return option_value->GetCurrentValue(); + return fail_value; +} + +bool +OptionValue::SetSInt64Value (int64_t new_value) +{ + OptionValueSInt64 *option_value = GetAsSInt64 (); + if (option_value) + { + option_value->SetCurrentValue(new_value); + return true; + } + return false; +} + +const char * +OptionValue::GetStringValue (const char *fail_value) const +{ + const OptionValueString *option_value = GetAsString (); + if (option_value) + return option_value->GetCurrentValue(); + return fail_value; +} + +bool +OptionValue::SetStringValue (const char *new_value) +{ + OptionValueString *option_value = GetAsString (); + if (option_value) + { + option_value->SetCurrentValue(new_value); + return true; + } + return false; +} + +uint64_t +OptionValue::GetUInt64Value (uint64_t fail_value) const +{ + const OptionValueUInt64 *option_value = GetAsUInt64 (); + if (option_value) + return option_value->GetCurrentValue(); + return fail_value; +} + +bool +OptionValue::SetUInt64Value (uint64_t new_value) +{ + OptionValueUInt64 *option_value = GetAsUInt64 (); + if (option_value) + { + option_value->SetCurrentValue(new_value); + return true; + } + return false; +} + +UUID +OptionValue::GetUUIDValue () const +{ + const OptionValueUUID *option_value = GetAsUUID(); + if (option_value) + return option_value->GetCurrentValue(); + return UUID(); +} + +bool +OptionValue::SetUUIDValue (const UUID &uuid) +{ + OptionValueUUID *option_value = GetAsUUID(); + if (option_value) + { + option_value->SetCurrentValue(uuid); + return true; + } + return false; +} + +const char * +OptionValue::GetBuiltinTypeAsCString (Type t) +{ + switch (t) + { + case eTypeInvalid: return "invalid"; + case eTypeArch: return "arch"; + case eTypeArgs: return "arguments"; + case eTypeArray: return "array"; + case eTypeBoolean: return "boolean"; + case eTypeDictionary: return "dictionary"; + case eTypeEnum: return "enum"; + case eTypeFileSpec: return "file"; + case eTypeFileSpecList: return "file-list"; + case eTypeFormat: return "format"; + case eTypePathMap: return "path-map"; + case eTypeProperties: return "properties"; + case eTypeRegex: return "regex"; + case eTypeSInt64: return "int"; + case eTypeString: return "string"; + case eTypeUInt64: return "unsigned"; + case eTypeUUID: return "uuid"; + } + return NULL; +} + + +lldb::OptionValueSP +OptionValue::CreateValueFromCStringForTypeMask (const char *value_cstr, uint32_t type_mask, Error &error) +{ + // If only 1 bit is set in the type mask for a dictionary or array + // then we know how to decode a value from a cstring + lldb::OptionValueSP value_sp; + switch (type_mask) + { + case 1u << eTypeArch: value_sp.reset(new OptionValueArch()); break; + case 1u << eTypeBoolean: value_sp.reset(new OptionValueBoolean(false)); break; + case 1u << eTypeFileSpec: value_sp.reset(new OptionValueFileSpec()); break; + case 1u << eTypeFormat: value_sp.reset(new OptionValueFormat(eFormatInvalid)); break; + case 1u << eTypeSInt64: value_sp.reset(new OptionValueSInt64()); break; + case 1u << eTypeString: value_sp.reset(new OptionValueString()); break; + case 1u << eTypeUInt64: value_sp.reset(new OptionValueUInt64()); break; + case 1u << eTypeUUID: value_sp.reset(new OptionValueUUID()); break; + } + + if (value_sp) + error = value_sp->SetValueFromCString (value_cstr, eVarSetOperationAssign); + else + error.SetErrorString("unsupported type mask"); + return value_sp; +} + +bool +OptionValue::DumpQualifiedName (Stream &strm) const +{ + bool dumped_something = false; + lldb::OptionValueSP m_parent_sp(m_parent_wp.lock()); + if (m_parent_sp) + { + if (m_parent_sp->DumpQualifiedName(strm)) + dumped_something = true; + } + ConstString name (GetName()); + if (name) + { + if (dumped_something) + strm.PutChar('.'); + else + dumped_something = true; + strm << name; + } + return dumped_something; +} + +size_t +OptionValue::AutoComplete (CommandInterpreter &interpreter, + const char *s, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches) +{ + word_complete = false; + matches.Clear(); + return matches.GetSize(); +} + +Error +OptionValue::SetValueFromCString (const char *value, VarSetOperationType op) +{ + Error error; + switch (op) + { + case eVarSetOperationReplace: + error.SetErrorStringWithFormat ("%s objects do not support the 'replace' operation", GetTypeAsCString()); + break; + case eVarSetOperationInsertBefore: + error.SetErrorStringWithFormat ("%s objects do not support the 'insert-before' operation", GetTypeAsCString()); + break; + case eVarSetOperationInsertAfter: + error.SetErrorStringWithFormat ("%s objects do not support the 'insert-after' operation", GetTypeAsCString()); + break; + case eVarSetOperationRemove: + error.SetErrorStringWithFormat ("%s objects do not support the 'remove' operation", GetTypeAsCString()); + break; + case eVarSetOperationAppend: + error.SetErrorStringWithFormat ("%s objects do not support the 'append' operation", GetTypeAsCString()); + break; + case eVarSetOperationClear: + error.SetErrorStringWithFormat ("%s objects do not support the 'clear' operation", GetTypeAsCString()); + break; + case eVarSetOperationAssign: + error.SetErrorStringWithFormat ("%s objects do not support the 'assign' operation", GetTypeAsCString()); + break; + case eVarSetOperationInvalid: + error.SetErrorStringWithFormat ("invalid operation performed on a %s object", GetTypeAsCString()); + break; + } + return error; +} + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArch.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArch.cpp new file mode 100644 index 0000000..92fedff --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArch.cpp @@ -0,0 +1,111 @@ +//===-- OptionValueArch.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/lldb-python.h" + +#include "lldb/Interpreter/OptionValueArch.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/State.h" +#include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Interpreter/CommandCompletions.h" + +using namespace lldb; +using namespace lldb_private; + +void +OptionValueArch::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) +{ + if (dump_mask & eDumpOptionType) + strm.Printf ("(%s)", GetTypeAsCString ()); + if (dump_mask & eDumpOptionValue) + { + if (dump_mask & eDumpOptionType) + strm.PutCString (" = "); + + if (m_current_value.IsValid()) + { + const char *arch_name = m_current_value.GetArchitectureName(); + if (arch_name) + strm.PutCString (arch_name); + } + } +} + +Error +OptionValueArch::SetValueFromCString (const char *value_cstr, VarSetOperationType op) +{ + Error error; + switch (op) + { + case eVarSetOperationClear: + Clear(); + break; + + case eVarSetOperationReplace: + case eVarSetOperationAssign: + if (value_cstr && value_cstr[0]) + { + if (m_current_value.SetTriple (value_cstr)) + m_value_was_set = true; + else + error.SetErrorStringWithFormat("unsupported architecture '%s'", value_cstr); + } + else + { + error.SetErrorString("invalid value string"); + } + break; + + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + case eVarSetOperationRemove: + case eVarSetOperationAppend: + case eVarSetOperationInvalid: + error = OptionValue::SetValueFromCString (value_cstr, op); + break; + } + return error; +} + +lldb::OptionValueSP +OptionValueArch::DeepCopy () const +{ + return OptionValueSP(new OptionValueArch(*this)); +} + + +size_t +OptionValueArch::AutoComplete (CommandInterpreter &interpreter, + const char *s, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches) +{ + word_complete = false; + matches.Clear(); + CommandCompletions::InvokeCommonCompletionCallbacks (interpreter, + CommandCompletions::eArchitectureCompletion, + s, + match_start_point, + max_return_elements, + NULL, + word_complete, + matches); + return matches.GetSize(); +} + + + + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArgs.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArgs.cpp new file mode 100644 index 0000000..e28d884 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArgs.cpp @@ -0,0 +1,38 @@ +//===-- OptionValueArgs.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/OptionValueArgs.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/Args.h" + +using namespace lldb; +using namespace lldb_private; + +size_t +OptionValueArgs::GetArgs (Args &args) +{ + const uint32_t size = m_values.size(); + std::vector<const char *> argv; + for (uint32_t i = 0; i<size; ++i) + { + const char *string_value = m_values[i]->GetStringValue (); + if (string_value) + argv.push_back(string_value); + } + + if (argv.empty()) + args.Clear(); + else + args.SetArguments(argv.size(), &argv[0]); + return args.GetArgumentCount(); +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArray.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArray.cpp new file mode 100644 index 0000000..9a01558 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArray.cpp @@ -0,0 +1,350 @@ +//===-- OptionValueArray.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/OptionValueArray.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Stream.h" +#include "lldb/Interpreter/Args.h" + +using namespace lldb; +using namespace lldb_private; + +void +OptionValueArray::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) +{ + const Type array_element_type = ConvertTypeMaskToType (m_type_mask); + if (dump_mask & eDumpOptionType) + { + if ((GetType() == eTypeArray) && (m_type_mask != eTypeInvalid)) + strm.Printf ("(%s of %ss)", GetTypeAsCString(), GetBuiltinTypeAsCString(array_element_type)); + else + strm.Printf ("(%s)", GetTypeAsCString()); + } + if (dump_mask & eDumpOptionValue) + { + if (dump_mask & eDumpOptionType) + strm.Printf (" =%s", (m_values.size() > 0) ? "\n" : ""); + strm.IndentMore(); + const uint32_t size = m_values.size(); + for (uint32_t i = 0; i<size; ++i) + { + strm.Indent(); + strm.Printf("[%u]: ", i); + const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0; + switch (array_element_type) + { + default: + case eTypeArray: + case eTypeDictionary: + case eTypeProperties: + case eTypeFileSpecList: + case eTypePathMap: + m_values[i]->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options); + break; + + case eTypeBoolean: + case eTypeEnum: + case eTypeFileSpec: + case eTypeFormat: + case eTypeSInt64: + case eTypeString: + case eTypeUInt64: + case eTypeUUID: + // No need to show the type for dictionaries of simple items + m_values[i]->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) | extra_dump_options); + break; + } + if (i < (size - 1)) + strm.EOL(); + } + strm.IndentLess(); + } +} + +Error +OptionValueArray::SetValueFromCString (const char *value, VarSetOperationType op) +{ + Args args(value); + return SetArgs (args, op); +} + + +lldb::OptionValueSP +OptionValueArray::GetSubValue (const ExecutionContext *exe_ctx, + const char *name, + bool will_modify, + Error &error) const +{ + if (name && name[0] == '[') + { + const char *end_bracket = strchr (name+1, ']'); + if (end_bracket) + { + const char *sub_value = NULL; + if (end_bracket[1]) + sub_value = end_bracket + 1; + std::string index_str (name+1, end_bracket); + const size_t array_count = m_values.size(); + int32_t idx = Args::StringToSInt32(index_str.c_str(), INT32_MAX, 0, NULL); + if (idx != INT32_MAX) + { + ; + uint32_t new_idx = UINT32_MAX; + if (idx < 0) + { + // Access from the end of the array if the index is negative + new_idx = array_count - idx; + } + else + { + // Just a standard index + new_idx = idx; + } + + if (new_idx < array_count) + { + if (m_values[new_idx]) + { + if (sub_value) + return m_values[new_idx]->GetSubValue (exe_ctx, sub_value, will_modify, error); + else + return m_values[new_idx]; + } + } + else + { + if (array_count == 0) + error.SetErrorStringWithFormat("index %i is not valid for an empty array", idx); + else if (idx > 0) + error.SetErrorStringWithFormat("index %i out of range, valid values are 0 through %" PRIu64, idx, (uint64_t)(array_count - 1)); + else + error.SetErrorStringWithFormat("negative index %i out of range, valid values are -1 through -%" PRIu64, idx, (uint64_t)array_count); + } + } + } + } + else + { + error.SetErrorStringWithFormat("invalid value path '%s', %s values only support '[<index>]' subvalues where <index> is a positive or negative array index", name, GetTypeAsCString()); + } + return OptionValueSP(); +} + + +size_t +OptionValueArray::GetArgs (Args &args) const +{ + const uint32_t size = m_values.size(); + std::vector<const char *> argv; + for (uint32_t i = 0; i<size; ++i) + { + const char *string_value = m_values[i]->GetStringValue (); + if (string_value) + argv.push_back(string_value); + } + + if (argv.empty()) + args.Clear(); + else + args.SetArguments(argv.size(), &argv[0]); + return args.GetArgumentCount(); +} + +Error +OptionValueArray::SetArgs (const Args &args, VarSetOperationType op) +{ + Error error; + const size_t argc = args.GetArgumentCount(); + switch (op) + { + case eVarSetOperationInvalid: + error.SetErrorString("unsupported operation"); + break; + + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + if (argc > 1) + { + uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); + const uint32_t count = GetSize(); + if (idx > count) + { + error.SetErrorStringWithFormat("invalid insert array index %u, index must be 0 through %u", idx, count); + } + else + { + if (op == eVarSetOperationInsertAfter) + ++idx; + for (size_t i=1; i<argc; ++i, ++idx) + { + lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (args.GetArgumentAtIndex(i), + m_type_mask, + error)); + if (value_sp) + { + if (error.Fail()) + return error; + if (idx >= m_values.size()) + m_values.push_back(value_sp); + else + m_values.insert(m_values.begin() + idx, value_sp); + } + else + { + error.SetErrorString("array of complex types must subclass OptionValueArray"); + return error; + } + } + } + } + else + { + error.SetErrorString("insert operation takes an array index followed by one or more values"); + } + break; + + case eVarSetOperationRemove: + if (argc > 0) + { + const uint32_t size = m_values.size(); + std::vector<int> remove_indexes; + bool all_indexes_valid = true; + size_t i; + for (i=0; i<argc; ++i) + { + const int idx = Args::StringToSInt32(args.GetArgumentAtIndex(i), INT32_MAX); + if (idx >= size) + { + all_indexes_valid = false; + break; + } + else + remove_indexes.push_back(idx); + } + + if (all_indexes_valid) + { + size_t num_remove_indexes = remove_indexes.size(); + if (num_remove_indexes) + { + // Sort and then erase in reverse so indexes are always valid + if (num_remove_indexes > 1) + { + std::sort(remove_indexes.begin(), remove_indexes.end()); + for (std::vector<int>::const_reverse_iterator pos = remove_indexes.rbegin(), end = remove_indexes.rend(); pos != end; ++pos) + { + m_values.erase(m_values.begin() + *pos); + } + } + else + { + // Only one index + m_values.erase(m_values.begin() + remove_indexes.front()); + } + } + } + else + { + error.SetErrorStringWithFormat("invalid array index '%s', aborting remove operation", args.GetArgumentAtIndex(i)); + } + } + else + { + error.SetErrorString("remove operation takes one or more array indices"); + } + break; + + case eVarSetOperationClear: + Clear (); + break; + + case eVarSetOperationReplace: + if (argc > 1) + { + uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); + const uint32_t count = GetSize(); + if (idx > count) + { + error.SetErrorStringWithFormat("invalid replace array index %u, index must be 0 through %u", idx, count); + } + else + { + for (size_t i=1; i<argc; ++i, ++idx) + { + lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (args.GetArgumentAtIndex(i), + m_type_mask, + error)); + if (value_sp) + { + if (error.Fail()) + return error; + if (idx < count) + m_values[idx] = value_sp; + else + m_values.push_back(value_sp); + } + else + { + error.SetErrorString("array of complex types must subclass OptionValueArray"); + return error; + } + } + } + } + else + { + error.SetErrorString("replace operation takes an array index followed by one or more values"); + } + break; + + case eVarSetOperationAssign: + m_values.clear(); + // Fall through to append case + case eVarSetOperationAppend: + for (size_t i=0; i<argc; ++i) + { + lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (args.GetArgumentAtIndex(i), + m_type_mask, + error)); + if (value_sp) + { + if (error.Fail()) + return error; + m_value_was_set = true; + AppendValue(value_sp); + } + else + { + error.SetErrorString("array of complex types must subclass OptionValueArray"); + } + } + break; + } + return error; +} + +lldb::OptionValueSP +OptionValueArray::DeepCopy () const +{ + OptionValueArray *copied_array = new OptionValueArray (m_type_mask, m_raw_value_dump); + lldb::OptionValueSP copied_value_sp(copied_array); + const uint32_t size = m_values.size(); + for (uint32_t i = 0; i<size; ++i) + { + copied_array->AppendValue (m_values[i]->DeepCopy()); + } + return copied_value_sp; +} + + + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueBoolean.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueBoolean.cpp new file mode 100644 index 0000000..6471943 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueBoolean.cpp @@ -0,0 +1,135 @@ +//===-- OptionValueBoolean.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/OptionValueBoolean.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Stream.h" +#include "lldb/Core/StringList.h" +#include "lldb/Interpreter/Args.h" + +using namespace lldb; +using namespace lldb_private; + +void +OptionValueBoolean::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) +{ + if (dump_mask & eDumpOptionType) + strm.Printf ("(%s)", GetTypeAsCString ()); +// if (dump_mask & eDumpOptionName) +// DumpQualifiedName (strm); + if (dump_mask & eDumpOptionValue) + { + if (dump_mask & eDumpOptionType) + strm.PutCString (" = "); + strm.PutCString (m_current_value ? "true" : "false"); + } +} + +Error +OptionValueBoolean::SetValueFromCString (const char *value_cstr, + VarSetOperationType op) +{ + Error error; + switch (op) + { + case eVarSetOperationClear: + Clear(); + break; + + case eVarSetOperationReplace: + case eVarSetOperationAssign: + { + bool success = false; + bool value = Args::StringToBoolean(value_cstr, false, &success); + if (success) + { + m_value_was_set = true; + m_current_value = value; + } + else + { + if (value_cstr == NULL) + error.SetErrorString ("invalid boolean string value: NULL"); + else if (value_cstr[0] == '\0') + error.SetErrorString ("invalid boolean string value <empty>"); + else + error.SetErrorStringWithFormat ("invalid boolean string value: '%s'", value_cstr); + } + } + break; + + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + case eVarSetOperationRemove: + case eVarSetOperationAppend: + case eVarSetOperationInvalid: + error = OptionValue::SetValueFromCString (value_cstr, op); + break; + } + return error; +} + +lldb::OptionValueSP +OptionValueBoolean::DeepCopy () const +{ + return OptionValueSP(new OptionValueBoolean(*this)); +} + +size_t +OptionValueBoolean::AutoComplete (CommandInterpreter &interpreter, + const char *s, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches) +{ + word_complete = false; + matches.Clear(); + struct StringEntry { + const char *string; + const size_t length; + }; + static const StringEntry g_autocomplete_entries[] = + { + { "true" , 4 }, + { "false", 5 }, + { "on" , 2 }, + { "off" , 3 }, + { "yes" , 3 }, + { "no" , 2 }, + { "1" , 1 }, + { "0" , 1 }, + }; + const size_t k_num_autocomplete_entries = sizeof(g_autocomplete_entries)/sizeof(StringEntry); + + if (s && s[0]) + { + const size_t s_len = strlen(s); + for (size_t i=0; i<k_num_autocomplete_entries; ++i) + { + if (s_len <= g_autocomplete_entries[i].length) + if (::strncasecmp(s, g_autocomplete_entries[i].string, s_len) == 0) + matches.AppendString(g_autocomplete_entries[i].string); + } + } + else + { + // only suggest "true" or "false" by default + for (size_t i=0; i<2; ++i) + matches.AppendString(g_autocomplete_entries[i].string); + } + return matches.GetSize(); +} + + + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueDictionary.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueDictionary.cpp new file mode 100644 index 0000000..61f8aba --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueDictionary.cpp @@ -0,0 +1,436 @@ +//===-- OptionValueDictionary.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/lldb-python.h" + +#include "lldb/Interpreter/OptionValueDictionary.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "llvm/ADT/StringRef.h" +// Project includes +#include "lldb/Core/State.h" +#include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Interpreter/OptionValueString.h" + +using namespace lldb; +using namespace lldb_private; + +void +OptionValueDictionary::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) +{ + const Type dict_type = ConvertTypeMaskToType (m_type_mask); + if (dump_mask & eDumpOptionType) + { + if (m_type_mask != eTypeInvalid) + strm.Printf ("(%s of %ss)", GetTypeAsCString(), GetBuiltinTypeAsCString(dict_type)); + else + strm.Printf ("(%s)", GetTypeAsCString()); + } + if (dump_mask & eDumpOptionValue) + { + if (dump_mask & eDumpOptionType) + strm.PutCString (" ="); + + collection::iterator pos, end = m_values.end(); + + strm.IndentMore(); + + for (pos = m_values.begin(); pos != end; ++pos) + { + OptionValue *option_value = pos->second.get(); + strm.EOL(); + strm.Indent(pos->first.GetCString()); + + const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0; + switch (dict_type) + { + default: + case eTypeArray: + case eTypeDictionary: + case eTypeProperties: + case eTypeFileSpecList: + case eTypePathMap: + strm.PutChar (' '); + option_value->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options); + break; + + case eTypeBoolean: + case eTypeEnum: + case eTypeFileSpec: + case eTypeFormat: + case eTypeSInt64: + case eTypeString: + case eTypeUInt64: + case eTypeUUID: + // No need to show the type for dictionaries of simple items + strm.PutCString("="); + option_value->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) | extra_dump_options); + break; + } + } + strm.IndentLess(); + } + +} + +size_t +OptionValueDictionary::GetArgs (Args &args) const +{ + args.Clear(); + collection::const_iterator pos, end = m_values.end(); + for (pos = m_values.begin(); pos != end; ++pos) + { + StreamString strm; + strm.Printf("%s=", pos->first.GetCString()); + pos->second->DumpValue(NULL, strm, eDumpOptionValue|eDumpOptionRaw); + args.AppendArgument(strm.GetString().c_str()); + } + return args.GetArgumentCount(); +} + +Error +OptionValueDictionary::SetArgs (const Args &args, VarSetOperationType op) +{ + Error error; + const size_t argc = args.GetArgumentCount(); + switch (op) + { + case eVarSetOperationClear: + Clear(); + break; + + case eVarSetOperationAppend: + case eVarSetOperationReplace: + case eVarSetOperationAssign: + if (argc > 0) + { + for (size_t i=0; i<argc; ++i) + { + llvm::StringRef key_and_value(args.GetArgumentAtIndex(i)); + if (!key_and_value.empty()) + { + std::pair<llvm::StringRef, llvm::StringRef> kvp(key_and_value.split('=')); + llvm::StringRef key = kvp.first; + bool key_valid = false; + if (!key.empty()) + { + if (key.front() == '[') + { + // Key name starts with '[', so the the key value must be in single or double quotes like: + // ['<key>'] + // ["<key>"] + if ((key.size() > 2) && (key.back() == ']')) + { + // Strip leading '[' and trailing ']' + key = key.substr(1, key.size()-2); + const char quote_char = key.front(); + if ((quote_char == '\'') || (quote_char == '"')) + { + if ((key.size() > 2) && (key.back() == quote_char)) + { + // Strip the quotes + key = key.substr(1, key.size()-2); + key_valid = true; + } + } + else + { + // square brackets, no quotes + key_valid = true; + } + } + } + else + { + // No square brackets or quotes + key_valid = true; + } + } + if (!key_valid) + { + error.SetErrorStringWithFormat("invalid key \"%s\", the key must be a bare string or surrounded by brackets with optional quotes: [<key>] or ['<key>'] or [\"<key>\"]", kvp.first.str().c_str()); + return error; + } + + lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (kvp.second.data(), + m_type_mask, + error)); + if (value_sp) + { + if (error.Fail()) + return error; + m_value_was_set = true; + SetValueForKey (ConstString(key), value_sp, true); + } + else + { + error.SetErrorString("dictionaries that can contain multiple types must subclass OptionValueArray"); + } + } + else + { + error.SetErrorString("empty argument"); + } + } + } + else + { + error.SetErrorString("assign operation takes one or more key=value arguments"); + } + break; + + case eVarSetOperationRemove: + if (argc > 0) + { + for (size_t i=0; i<argc; ++i) + { + ConstString key(args.GetArgumentAtIndex(i)); + if (!DeleteValueForKey(key)) + { + error.SetErrorStringWithFormat("no value found named '%s', aborting remove operation", key.GetCString()); + break; + } + } + } + else + { + error.SetErrorString("remove operation takes one or more key arguments"); + } + break; + + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + case eVarSetOperationInvalid: + error = OptionValue::SetValueFromCString (NULL, op); + break; + } + return error; +} + +Error +OptionValueDictionary::SetValueFromCString (const char *value_cstr, VarSetOperationType op) +{ + Args args(value_cstr); + return SetArgs (args, op); +} + +lldb::OptionValueSP +OptionValueDictionary::GetSubValue (const ExecutionContext *exe_ctx, const char *name, bool will_modify, Error &error) const +{ + lldb::OptionValueSP value_sp; + + if (name && name[0]) + { + const char *sub_name = NULL; + ConstString key; + const char *open_bracket = ::strchr (name, '['); + + if (open_bracket) + { + const char *key_start = open_bracket + 1; + const char *key_end = NULL; + switch (open_bracket[1]) + { + case '\'': + ++key_start; + key_end = strchr(key_start, '\''); + if (key_end) + { + if (key_end[1] == ']') + { + if (key_end[2]) + sub_name = key_end + 2; + } + else + { + error.SetErrorStringWithFormat ("invalid value path '%s', single quoted key names must be formatted as ['<key>'] where <key> is a string that doesn't contain quotes", name); + return value_sp; + } + } + else + { + error.SetErrorString ("missing '] key name terminator, key name started with ['"); + return value_sp; + } + break; + case '"': + ++key_start; + key_end = strchr(key_start, '"'); + if (key_end) + { + if (key_end[1] == ']') + { + if (key_end[2]) + sub_name = key_end + 2; + break; + } + error.SetErrorStringWithFormat ("invalid value path '%s', double quoted key names must be formatted as [\"<key>\"] where <key> is a string that doesn't contain quotes", name); + return value_sp; + } + else + { + error.SetErrorString ("missing \"] key name terminator, key name started with [\""); + return value_sp; + } + break; + + default: + key_end = strchr(key_start, ']'); + if (key_end) + { + if (key_end[1]) + sub_name = key_end + 1; + } + else + { + error.SetErrorString ("missing ] key name terminator, key name started with ["); + return value_sp; + } + break; + } + + if (key_start && key_end) + { + key.SetCStringWithLength (key_start, key_end - key_start); + + value_sp = GetValueForKey (key); + if (value_sp) + { + if (sub_name) + return value_sp->GetSubValue (exe_ctx, sub_name, will_modify, error); + } + else + { + error.SetErrorStringWithFormat("dictionary does not contain a value for the key name '%s'", key.GetCString()); + } + } + } + if (!value_sp && error.AsCString() == NULL) + { + error.SetErrorStringWithFormat ("invalid value path '%s', %s values only support '[<key>]' subvalues where <key> a string value optionally delimitted by single or double quotes", + name, + GetTypeAsCString()); + } + } + return value_sp; +} + +Error +OptionValueDictionary::SetSubValue (const ExecutionContext *exe_ctx, VarSetOperationType op, const char *name, const char *value) +{ + Error error; + const bool will_modify = true; + lldb::OptionValueSP value_sp (GetSubValue (exe_ctx, name, will_modify, error)); + if (value_sp) + error = value_sp->SetValueFromCString(value, op); + else + { + if (error.AsCString() == NULL) + error.SetErrorStringWithFormat("invalid value path '%s'", name); + } + return error; +} + + +lldb::OptionValueSP +OptionValueDictionary::GetValueForKey (const ConstString &key) const +{ + lldb::OptionValueSP value_sp; + collection::const_iterator pos = m_values.find (key); + if (pos != m_values.end()) + value_sp = pos->second; + return value_sp; +} + +const char * +OptionValueDictionary::GetStringValueForKey (const ConstString &key) +{ + collection::const_iterator pos = m_values.find (key); + if (pos != m_values.end()) + { + OptionValueString *string_value = pos->second->GetAsString(); + if (string_value) + return string_value->GetCurrentValue(); + } + return NULL; +} + + +bool +OptionValueDictionary::SetStringValueForKey (const ConstString &key, + const char *value, + bool can_replace) +{ + collection::const_iterator pos = m_values.find (key); + if (pos != m_values.end()) + { + if (!can_replace) + return false; + if (pos->second->GetType() == OptionValue::eTypeString) + { + pos->second->SetValueFromCString(value); + return true; + } + } + m_values[key] = OptionValueSP (new OptionValueString (value)); + return true; + +} + +bool +OptionValueDictionary::SetValueForKey (const ConstString &key, + const lldb::OptionValueSP &value_sp, + bool can_replace) +{ + // Make sure the value_sp object is allowed to contain + // values of the type passed in... + if (value_sp && (m_type_mask & value_sp->GetTypeAsMask())) + { + if (!can_replace) + { + collection::const_iterator pos = m_values.find (key); + if (pos != m_values.end()) + return false; + } + m_values[key] = value_sp; + return true; + } + return false; +} + +bool +OptionValueDictionary::DeleteValueForKey (const ConstString &key) +{ + collection::iterator pos = m_values.find (key); + if (pos != m_values.end()) + { + m_values.erase(pos); + return true; + } + return false; +} + +lldb::OptionValueSP +OptionValueDictionary::DeepCopy () const +{ + OptionValueDictionary *copied_dict = new OptionValueDictionary (m_type_mask, m_raw_value_dump); + lldb::OptionValueSP copied_value_sp(copied_dict); + collection::const_iterator pos, end = m_values.end(); + for (pos = m_values.begin(); pos != end; ++pos) + { + StreamString strm; + strm.Printf("%s=", pos->first.GetCString()); + copied_dict->SetValueForKey (pos->first, pos->second->DeepCopy(), true); + } + return copied_value_sp; +} + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueEnumeration.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueEnumeration.cpp new file mode 100644 index 0000000..f282235 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueEnumeration.cpp @@ -0,0 +1,166 @@ +//===-- OptionValueEnumeration.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/OptionValueEnumeration.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/StringList.h" + +using namespace lldb; +using namespace lldb_private; + +OptionValueEnumeration::OptionValueEnumeration (const OptionEnumValueElement *enumerators, + enum_type value) : + OptionValue(), + m_current_value (value), + m_default_value (value), + m_enumerations () +{ + SetEnumerations(enumerators); +} + +OptionValueEnumeration::~OptionValueEnumeration() +{ +} + +void +OptionValueEnumeration::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) +{ + if (dump_mask & eDumpOptionType) + strm.Printf ("(%s)", GetTypeAsCString ()); + if (dump_mask & eDumpOptionValue) + { + if (dump_mask & eDumpOptionType) + strm.PutCString (" = "); + const size_t count = m_enumerations.GetSize (); + for (size_t i=0; i<count; ++i) + { + if (m_enumerations.GetValueAtIndexUnchecked(i).value == m_current_value) + { + strm.PutCString(m_enumerations.GetCStringAtIndex(i)); + return; + } + } + strm.Printf("%" PRIu64, (uint64_t)m_current_value); + } +} + +Error +OptionValueEnumeration::SetValueFromCString (const char *value, VarSetOperationType op) +{ + Error error; + switch (op) + { + case eVarSetOperationClear: + Clear (); + break; + + case eVarSetOperationReplace: + case eVarSetOperationAssign: + if (value && value[0]) + { + ConstString const_enumerator_name(value); + const EnumerationMapEntry *enumerator_entry = m_enumerations.FindFirstValueForName (const_enumerator_name.GetCString()); + if (enumerator_entry) + { + m_current_value = enumerator_entry->value.value; + } + else + { + StreamString error_strm; + error_strm.Printf("invalid enumeration value '%s'", value); + const size_t count = m_enumerations.GetSize (); + if (count) + { + error_strm.Printf(", valid values are: %s", m_enumerations.GetCStringAtIndex(0)); + for (size_t i=1; i<count; ++i) + { + error_strm.Printf (", %s", m_enumerations.GetCStringAtIndex(i)); + } + } + error.SetErrorString(error_strm.GetData()); + } + } + else + { + error.SetErrorString("invalid enumeration value"); + } + break; + + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + case eVarSetOperationRemove: + case eVarSetOperationAppend: + case eVarSetOperationInvalid: + error = OptionValue::SetValueFromCString (value, op); + break; + } + return error; +} + +void +OptionValueEnumeration::SetEnumerations (const OptionEnumValueElement *enumerators) +{ + m_enumerations.Clear(); + if (enumerators) + { + for (size_t i=0; enumerators[i].string_value != NULL; ++i) + { + ConstString const_enumerator_name(enumerators[i].string_value); + EnumeratorInfo enumerator_info = { enumerators[i].value, enumerators[i].usage }; + m_enumerations.Append (const_enumerator_name.GetCString(), enumerator_info); + } + m_enumerations.Sort(); + } +} + + +lldb::OptionValueSP +OptionValueEnumeration::DeepCopy () const +{ + return OptionValueSP(new OptionValueEnumeration(*this)); +} + +size_t +OptionValueEnumeration::AutoComplete (CommandInterpreter &interpreter, + const char *s, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches) +{ + word_complete = false; + matches.Clear(); + + const uint32_t num_enumerators = m_enumerations.GetSize(); + if (s && s[0]) + { + const size_t s_len = strlen(s); + for (size_t i=0; i<num_enumerators; ++i) + { + const char *name = m_enumerations.GetCStringAtIndex(i); + if (::strncmp(s, name, s_len) == 0) + matches.AppendString(name); + } + } + else + { + // only suggest "true" or "false" by default + for (size_t i=0; i<num_enumerators; ++i) + matches.AppendString(m_enumerations.GetCStringAtIndex(i)); + } + return matches.GetSize(); +} + + + + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpec.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpec.cpp new file mode 100644 index 0000000..e56b48b --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpec.cpp @@ -0,0 +1,159 @@ +//===-- OptionValueFileSpec.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/lldb-python.h" + +#include "lldb/Interpreter/OptionValueFileSpec.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/State.h" +#include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Interpreter/CommandCompletions.h" + +using namespace lldb; +using namespace lldb_private; + + +OptionValueFileSpec::OptionValueFileSpec () : + OptionValue(), + m_current_value (), + m_default_value (), + m_data_sp(), + m_completion_mask (CommandCompletions::eDiskFileCompletion) +{ +} + +OptionValueFileSpec::OptionValueFileSpec (const FileSpec &value) : + OptionValue(), + m_current_value (value), + m_default_value (value), + m_data_sp(), + m_completion_mask (CommandCompletions::eDiskFileCompletion) +{ +} + +OptionValueFileSpec::OptionValueFileSpec (const FileSpec ¤t_value, + const FileSpec &default_value) : + OptionValue(), + m_current_value (current_value), + m_default_value (default_value), + m_data_sp(), + m_completion_mask (CommandCompletions::eDiskFileCompletion) +{ +} + +void +OptionValueFileSpec::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) +{ + if (dump_mask & eDumpOptionType) + strm.Printf ("(%s)", GetTypeAsCString ()); + if (dump_mask & eDumpOptionValue) + { + if (dump_mask & eDumpOptionType) + strm.PutCString (" = "); + + if (m_current_value) + { + strm << '"' << m_current_value.GetPath().c_str() << '"'; + } + } +} + +Error +OptionValueFileSpec::SetValueFromCString (const char *value_cstr, + VarSetOperationType op) +{ + Error error; + switch (op) + { + case eVarSetOperationClear: + Clear (); + break; + + case eVarSetOperationReplace: + case eVarSetOperationAssign: + if (value_cstr && value_cstr[0]) + { + Args args(value_cstr); + if (args.GetArgumentCount() == 1) + { + const char *path = args.GetArgumentAtIndex(0); + m_value_was_set = true; + m_current_value.SetFile(path, true); + } + else + { + error.SetErrorString("please supply a single path argument for this file or quote the path if it contains spaces"); + } + } + else + { + error.SetErrorString("invalid value string"); + } + break; + + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + case eVarSetOperationRemove: + case eVarSetOperationAppend: + case eVarSetOperationInvalid: + error = OptionValue::SetValueFromCString (value_cstr, op); + break; + } + return error; +} + +lldb::OptionValueSP +OptionValueFileSpec::DeepCopy () const +{ + return OptionValueSP(new OptionValueFileSpec(*this)); +} + + +size_t +OptionValueFileSpec::AutoComplete (CommandInterpreter &interpreter, + const char *s, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches) +{ + word_complete = false; + matches.Clear(); + CommandCompletions::InvokeCommonCompletionCallbacks (interpreter, + m_completion_mask, + s, + match_start_point, + max_return_elements, + NULL, + word_complete, + matches); + return matches.GetSize(); +} + + + +const lldb::DataBufferSP & +OptionValueFileSpec::GetFileContents(bool null_terminate) +{ + if (!m_data_sp && m_current_value) + { + if (null_terminate) + m_data_sp = m_current_value.ReadFileContentsAsCString(); + else + m_data_sp = m_current_value.ReadFileContents(); + } + return m_data_sp; +} + + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpecLIst.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpecLIst.cpp new file mode 100644 index 0000000..e493c70 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpecLIst.cpp @@ -0,0 +1,186 @@ +//===-- OptionValueFileSpecList.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/OptionValueFileSpecList.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Stream.h" +#include "lldb/Interpreter/Args.h" + +using namespace lldb; +using namespace lldb_private; + +void +OptionValueFileSpecList::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) +{ + if (dump_mask & eDumpOptionType) + strm.Printf ("(%s)", GetTypeAsCString ()); + if (dump_mask & eDumpOptionValue) + { + if (dump_mask & eDumpOptionType) + strm.Printf (" =%s", m_current_value.GetSize() > 0 ? "\n" : ""); + strm.IndentMore(); + const uint32_t size = m_current_value.GetSize(); + for (uint32_t i = 0; i<size; ++i) + { + strm.Indent(); + strm.Printf("[%u]: ", i); + m_current_value.GetFileSpecAtIndex(i).Dump(&strm); + } + strm.IndentLess(); + } +} + +Error +OptionValueFileSpecList::SetValueFromCString (const char *value, VarSetOperationType op) +{ + Error error; + Args args(value); + const size_t argc = args.GetArgumentCount(); + + switch (op) + { + case eVarSetOperationClear: + Clear (); + break; + + case eVarSetOperationReplace: + if (argc > 1) + { + uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); + const uint32_t count = m_current_value.GetSize(); + if (idx > count) + { + error.SetErrorStringWithFormat("invalid file list index %u, index must be 0 through %u", idx, count); + } + else + { + for (size_t i=1; i<argc; ++i, ++idx) + { + FileSpec file (args.GetArgumentAtIndex(i), false); + if (idx < count) + m_current_value.Replace(idx, file); + else + m_current_value.Append(file); + } + } + } + else + { + error.SetErrorString("replace operation takes an array index followed by one or more values"); + } + break; + + + + case eVarSetOperationAssign: + m_current_value.Clear(); + // Fall through to append case + case eVarSetOperationAppend: + if (argc > 0) + { + m_value_was_set = true; + for (size_t i=0; i<argc; ++i) + { + FileSpec file (args.GetArgumentAtIndex(i), false); + m_current_value.Append(file); + } + } + else + { + error.SetErrorString("assign operation takes at least one file path argument"); + } + break; + + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + if (argc > 1) + { + uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); + const uint32_t count = m_current_value.GetSize(); + if (idx > count) + { + error.SetErrorStringWithFormat("invalid insert file list index %u, index must be 0 through %u", idx, count); + } + else + { + if (op == eVarSetOperationInsertAfter) + ++idx; + for (size_t i=1; i<argc; ++i, ++idx) + { + FileSpec file (args.GetArgumentAtIndex(i), false); + m_current_value.Insert (idx, file); + } + } + } + else + { + error.SetErrorString("insert operation takes an array index followed by one or more values"); + } + break; + + case eVarSetOperationRemove: + if (argc > 0) + { + std::vector<int> remove_indexes; + bool all_indexes_valid = true; + size_t i; + for (i=0; all_indexes_valid && i<argc; ++i) + { + const int idx = Args::StringToSInt32(args.GetArgumentAtIndex(i), INT32_MAX); + if (idx == INT32_MAX) + all_indexes_valid = false; + else + remove_indexes.push_back(idx); + } + + if (all_indexes_valid) + { + size_t num_remove_indexes = remove_indexes.size(); + if (num_remove_indexes) + { + // Sort and then erase in reverse so indexes are always valid + std::sort(remove_indexes.begin(), remove_indexes.end()); + for (size_t j=num_remove_indexes-1; j<num_remove_indexes; ++j) + { + m_current_value.Remove (j); + } + } + } + else + { + error.SetErrorStringWithFormat("invalid array index '%s', aborting remove operation", args.GetArgumentAtIndex(i)); + } + } + else + { + error.SetErrorString("remove operation takes one or more array index"); + } + break; + + case eVarSetOperationInvalid: + error = OptionValue::SetValueFromCString (value, op); + break; + } + return error; + + m_value_was_set = true; + return Error(); +} + +lldb::OptionValueSP +OptionValueFileSpecList::DeepCopy () const +{ + return OptionValueSP(new OptionValueFileSpecList(*this)); +} + + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFormat.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFormat.cpp new file mode 100644 index 0000000..34d3672 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFormat.cpp @@ -0,0 +1,78 @@ +//===-- OptionValueFormat.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/lldb-python.h" + +#include "lldb/Interpreter/OptionValueFormat.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Stream.h" +#include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Interpreter/Args.h" + +using namespace lldb; +using namespace lldb_private; + +void +OptionValueFormat::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) +{ + if (dump_mask & eDumpOptionType) + strm.Printf ("(%s)", GetTypeAsCString ()); + if (dump_mask & eDumpOptionValue) + { + if (dump_mask & eDumpOptionType) + strm.PutCString (" = "); + strm.PutCString (FormatManager::GetFormatAsCString (m_current_value)); + } +} + +Error +OptionValueFormat::SetValueFromCString (const char *value_cstr, VarSetOperationType op) +{ + Error error; + switch (op) + { + case eVarSetOperationClear: + Clear(); + break; + + case eVarSetOperationReplace: + case eVarSetOperationAssign: + { + Format new_format; + error = Args::StringToFormat (value_cstr, new_format, NULL); + if (error.Success()) + { + m_value_was_set = true; + m_current_value = new_format; + } + } + break; + + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + case eVarSetOperationRemove: + case eVarSetOperationAppend: + case eVarSetOperationInvalid: + error = OptionValue::SetValueFromCString (value_cstr, op); + break; + } + return error; +} + + +lldb::OptionValueSP +OptionValueFormat::DeepCopy () const +{ + return OptionValueSP(new OptionValueFormat(*this)); +} + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValuePathMappings.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValuePathMappings.cpp new file mode 100644 index 0000000..88a0eb7 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValuePathMappings.cpp @@ -0,0 +1,185 @@ +//===-- OptionValuePathMappings.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/OptionValuePathMappings.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Stream.h" +#include "lldb/Interpreter/Args.h" + +using namespace lldb; +using namespace lldb_private; + +void +OptionValuePathMappings::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) +{ + if (dump_mask & eDumpOptionType) + strm.Printf ("(%s)", GetTypeAsCString ()); + if (dump_mask & eDumpOptionValue) + { + if (dump_mask & eDumpOptionType) + strm.Printf (" =%s", (m_path_mappings.GetSize() > 0) ? "\n" : ""); + m_path_mappings.Dump(&strm); + } +} + +Error +OptionValuePathMappings::SetValueFromCString (const char *value, VarSetOperationType op) +{ + Error error; + Args args(value); + const size_t argc = args.GetArgumentCount(); + + switch (op) + { + case eVarSetOperationClear: + Clear (); + break; + + case eVarSetOperationReplace: + // Must be at least one index + 1 pair of paths, and the pair count must be even + if (argc >= 3 && (((argc - 1) & 1) == 0)) + { + uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); + const uint32_t count = m_path_mappings.GetSize(); + if (idx > count) + { + error.SetErrorStringWithFormat("invalid file list index %u, index must be 0 through %u", idx, count); + } + else + { + for (size_t i=1; i<argc; i += 2, ++idx) + { + ConstString a(args.GetArgumentAtIndex(i)); + ConstString b(args.GetArgumentAtIndex(i+1)); + if (!m_path_mappings.Replace (a, b, idx, m_notify_changes)) + m_path_mappings.Append(a, b, m_notify_changes); + } + } + } + else + { + error.SetErrorString("replace operation takes an array index followed by one or more path pairs"); + } + break; + + + + case eVarSetOperationAssign: + if (argc < 2 || (argc & 1)) + { + error.SetErrorString("assign operation takes one or more path pairs"); + break; + } + m_path_mappings.Clear(m_notify_changes); + // Fall through to append case + case eVarSetOperationAppend: + if (argc < 2 || (argc & 1)) + { + error.SetErrorString("append operation takes one or more path pairs"); + break; + } + else + { + for (size_t i=0; i<argc; i += 2) + { + ConstString a(args.GetArgumentAtIndex(i)); + ConstString b(args.GetArgumentAtIndex(i+1)); + m_path_mappings.Append(a, b, m_notify_changes); + m_value_was_set = true; + } + } + break; + + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + // Must be at least one index + 1 pair of paths, and the pair count must be even + if (argc >= 3 && (((argc - 1) & 1) == 0)) + { + uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); + const uint32_t count = m_path_mappings.GetSize(); + if (idx > count) + { + error.SetErrorStringWithFormat("invalid file list index %u, index must be 0 through %u", idx, count); + } + else + { + if (op == eVarSetOperationInsertAfter) + ++idx; + for (size_t i=1; i<argc; i += 2, ++idx) + { + ConstString a(args.GetArgumentAtIndex(i)); + ConstString b(args.GetArgumentAtIndex(i+1)); + m_path_mappings.Insert (a, b, idx, m_notify_changes); + } + } + } + else + { + error.SetErrorString("insert operation takes an array index followed by one or more path pairs"); + } + break; + + case eVarSetOperationRemove: + if (argc > 0) + { + std::vector<int> remove_indexes; + bool all_indexes_valid = true; + size_t i; + for (i=0; all_indexes_valid && i<argc; ++i) + { + const int idx = Args::StringToSInt32(args.GetArgumentAtIndex(i), INT32_MAX); + if (idx == INT32_MAX) + all_indexes_valid = false; + else + remove_indexes.push_back(idx); + } + + if (all_indexes_valid) + { + size_t num_remove_indexes = remove_indexes.size(); + if (num_remove_indexes) + { + // Sort and then erase in reverse so indexes are always valid + std::sort(remove_indexes.begin(), remove_indexes.end()); + for (size_t j=num_remove_indexes-1; j<num_remove_indexes; ++j) + { + m_path_mappings.Remove (j, m_notify_changes); + } + } + } + else + { + error.SetErrorStringWithFormat("invalid array index '%s', aborting remove operation", args.GetArgumentAtIndex(i)); + } + } + else + { + error.SetErrorString("remove operation takes one or more array index"); + } + break; + + case eVarSetOperationInvalid: + error = OptionValue::SetValueFromCString (value, op); + break; + } + return error; + + m_value_was_set = true; + return Error(); +} + +lldb::OptionValueSP +OptionValuePathMappings::DeepCopy () const +{ + return OptionValueSP(new OptionValuePathMappings(*this)); +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueProperties.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueProperties.cpp new file mode 100644 index 0000000..0df3782 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueProperties.cpp @@ -0,0 +1,762 @@ +//===-- OptionValueProperties.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/OptionValueProperties.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Flags.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StringList.h" +#include "lldb/Core/UserSettingsController.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Interpreter/OptionValues.h" +#include "lldb/Interpreter/Property.h" + +using namespace lldb; +using namespace lldb_private; + + +OptionValueProperties::OptionValueProperties (const ConstString &name) : + OptionValue (), + m_name (name), + m_properties (), + m_name_to_index () +{ +} + +OptionValueProperties::OptionValueProperties (const OptionValueProperties &global_properties) : + OptionValue (global_properties), + m_name (global_properties.m_name), + m_properties (global_properties.m_properties), + m_name_to_index (global_properties.m_name_to_index) +{ + // We now have an exact copy of "global_properties". We need to now + // find all non-global settings and copy the property values so that + // all non-global settings get new OptionValue instances created for + // them. + const size_t num_properties = m_properties.size(); + for (size_t i=0; i<num_properties; ++i) + { + // Duplicate any values that are not global when contructing properties from + // a global copy + if (m_properties[i].IsGlobal() == false) + { + lldb::OptionValueSP new_value_sp (m_properties[i].GetValue()->DeepCopy()); + m_properties[i].SetOptionValue(new_value_sp); + } + } +} + + + +size_t +OptionValueProperties::GetNumProperties() const +{ + return m_properties.size(); +} + + +void +OptionValueProperties::Initialize (const PropertyDefinition *defs) +{ + for (size_t i=0; defs[i].name; ++i) + { + Property property(defs[i]); + assert(property.IsValid()); + m_name_to_index.Append(property.GetName().GetCString(),m_properties.size()); + property.GetValue()->SetParent(shared_from_this()); + m_properties.push_back(property); + } + m_name_to_index.Sort(); +} + +void +OptionValueProperties::AppendProperty(const ConstString &name, + const ConstString &desc, + bool is_global, + const OptionValueSP &value_sp) +{ + Property property(name, desc, is_global, value_sp); + m_name_to_index.Append(name.GetCString(),m_properties.size()); + m_properties.push_back(property); + value_sp->SetParent (shared_from_this()); + m_name_to_index.Sort(); +} + + + +//bool +//OptionValueProperties::GetQualifiedName (Stream &strm) +//{ +// bool dumped_something = false; +//// lldb::OptionValuePropertiesSP parent_sp(GetParent ()); +//// if (parent_sp) +//// { +//// parent_sp->GetQualifiedName (strm); +//// strm.PutChar('.'); +//// dumped_something = true; +//// } +// if (m_name) +// { +// strm << m_name; +// dumped_something = true; +// } +// return dumped_something; +//} +// +lldb::OptionValueSP +OptionValueProperties::GetValueForKey (const ExecutionContext *exe_ctx, + const ConstString &key, + bool will_modify) const +{ + lldb::OptionValueSP value_sp; + size_t idx = m_name_to_index.Find (key.GetCString(), SIZE_MAX); + if (idx < m_properties.size()) + value_sp = GetPropertyAtIndex(exe_ctx, will_modify, idx)->GetValue(); + return value_sp; +} + +lldb::OptionValueSP +OptionValueProperties::GetSubValue (const ExecutionContext *exe_ctx, + const char *name, + bool will_modify, + Error &error) const +{ + lldb::OptionValueSP value_sp; + + if (name && name[0]) + { + const char *sub_name = NULL; + ConstString key; + size_t key_len = ::strcspn (name, ".[{"); + + if (name[key_len]) + { + key.SetCStringWithLength (name, key_len); + sub_name = name + key_len; + } + else + key.SetCString (name); + + value_sp = GetValueForKey (exe_ctx, key, will_modify); + if (sub_name && value_sp) + { + switch (sub_name[0]) + { + case '.': + return value_sp->GetSubValue (exe_ctx, sub_name + 1, will_modify, error); + + case '{': + // Predicate matching for predicates like + // "<setting-name>{<predicate>}" + // strings are parsed by the current OptionValueProperties subclass + // to mean whatever they want to. For instance a subclass of + // OptionValueProperties for a lldb_private::Target might implement: + // "target.run-args{arch==i386}" -- only set run args if the arch is i386 + // "target.run-args{path=/tmp/a/b/c/a.out}" -- only set run args if the path matches + // "target.run-args{basename==test&&arch==x86_64}" -- only set run args if exectable basename is "test" and arch is "x86_64" + if (sub_name[1]) + { + const char *predicate_start = sub_name + 1; + const char *predicate_end = strchr(predicate_start, '}'); + if (predicate_end) + { + std::string predicate(predicate_start, predicate_end); + if (PredicateMatches(exe_ctx, predicate.c_str())) + { + if (predicate_end[1]) + { + // Still more subvalue string to evaluate + return value_sp->GetSubValue (exe_ctx, predicate_end + 1, will_modify, error); + } + else + { + // We have a match! + break; + } + } + } + } + // Predicate didn't match or wasn't correctly formed + value_sp.reset(); + break; + + case '[': + // Array or dictionary access for subvalues like: + // "[12]" -- access 12th array element + // "['hello']" -- dictionary access of key named hello + return value_sp->GetSubValue (exe_ctx, sub_name, will_modify, error); + + default: + value_sp.reset(); + break; + } + } + } + return value_sp; +} + +Error +OptionValueProperties::SetSubValue (const ExecutionContext *exe_ctx, + VarSetOperationType op, + const char *name, + const char *value) +{ + Error error; + const bool will_modify = true; + lldb::OptionValueSP value_sp (GetSubValue (exe_ctx, name, will_modify, error)); + if (value_sp) + error = value_sp->SetValueFromCString(value, op); + else + { + if (error.AsCString() == NULL) + error.SetErrorStringWithFormat("invalid value path '%s'", name); + } + return error; +} + + +ConstString +OptionValueProperties::GetPropertyNameAtIndex (uint32_t idx) const +{ + const Property *property = GetPropertyAtIndex(NULL, false, idx); + if (property) + return property->GetName(); + return ConstString(); + +} + +const char * +OptionValueProperties::GetPropertyDescriptionAtIndex (uint32_t idx) const +{ + const Property *property = GetPropertyAtIndex(NULL, false, idx); + if (property) + return property->GetDescription(); + return NULL; +} + +uint32_t +OptionValueProperties::GetPropertyIndex (const ConstString &name) const +{ + return m_name_to_index.Find (name.GetCString(), SIZE_MAX); +} + +const Property * +OptionValueProperties::GetProperty (const ExecutionContext *exe_ctx, bool will_modify, const ConstString &name) const +{ + return GetPropertyAtIndex (exe_ctx, will_modify, m_name_to_index.Find (name.GetCString(), SIZE_MAX)); +} + +const Property * +OptionValueProperties::GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const +{ + return ProtectedGetPropertyAtIndex (idx); +} + +lldb::OptionValueSP +OptionValueProperties::GetPropertyValueAtIndex (const ExecutionContext *exe_ctx, + bool will_modify, + uint32_t idx) const +{ + const Property *setting = GetPropertyAtIndex (exe_ctx, will_modify, idx); + if (setting) + return setting->GetValue(); + return OptionValueSP(); +} + +OptionValuePathMappings * +OptionValueProperties::GetPropertyAtIndexAsOptionValuePathMappings (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const +{ + OptionValueSP value_sp(GetPropertyValueAtIndex (exe_ctx, will_modify, idx)); + if (value_sp) + return value_sp->GetAsPathMappings(); + return NULL; +} + +OptionValueFileSpecList * +OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpecList (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const +{ + OptionValueSP value_sp(GetPropertyValueAtIndex (exe_ctx, will_modify, idx)); + if (value_sp) + return value_sp->GetAsFileSpecList(); + return NULL; +} + +OptionValueArch * +OptionValueProperties::GetPropertyAtIndexAsOptionValueArch (const ExecutionContext *exe_ctx, uint32_t idx) const +{ + const Property *property = GetPropertyAtIndex (exe_ctx, false, idx); + if (property) + return property->GetValue()->GetAsArch(); + return NULL; +} + +bool +OptionValueProperties::GetPropertyAtIndexAsArgs (const ExecutionContext *exe_ctx, uint32_t idx, Args &args) const +{ + const Property *property = GetPropertyAtIndex (exe_ctx, false, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + { + const OptionValueArray *array = value->GetAsArray(); + if (array) + return array->GetArgs(args); + else + { + const OptionValueDictionary *dict = value->GetAsDictionary(); + if (dict) + return dict->GetArgs(args); + } + } + } + return false; +} + +bool +OptionValueProperties::SetPropertyAtIndexFromArgs (const ExecutionContext *exe_ctx, uint32_t idx, const Args &args) +{ + const Property *property = GetPropertyAtIndex (exe_ctx, true, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + { + OptionValueArray *array = value->GetAsArray(); + if (array) + return array->SetArgs(args, eVarSetOperationAssign).Success(); + else + { + OptionValueDictionary *dict = value->GetAsDictionary(); + if (dict) + return dict->SetArgs(args, eVarSetOperationAssign).Success(); + } + } + } + return false; +} + +bool +OptionValueProperties::GetPropertyAtIndexAsBoolean (const ExecutionContext *exe_ctx, uint32_t idx, bool fail_value) const +{ + const Property *property = GetPropertyAtIndex (exe_ctx, false, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + return value->GetBooleanValue(fail_value); + } + return fail_value; +} + +bool +OptionValueProperties::SetPropertyAtIndexAsBoolean (const ExecutionContext *exe_ctx, uint32_t idx, bool new_value) +{ + const Property *property = GetPropertyAtIndex (exe_ctx, true, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + { + value->SetBooleanValue(new_value); + return true; + } + } + return false; +} + +OptionValueDictionary * +OptionValueProperties::GetPropertyAtIndexAsOptionValueDictionary (const ExecutionContext *exe_ctx, uint32_t idx) const +{ + const Property *property = GetPropertyAtIndex (exe_ctx, false, idx); + if (property) + return property->GetValue()->GetAsDictionary(); + return NULL; +} + +int64_t +OptionValueProperties::GetPropertyAtIndexAsEnumeration (const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const +{ + const Property *property = GetPropertyAtIndex (exe_ctx, false, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + return value->GetEnumerationValue(fail_value); + } + return fail_value; +} + +bool +OptionValueProperties::SetPropertyAtIndexAsEnumeration (const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value) +{ + const Property *property = GetPropertyAtIndex (exe_ctx, true, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + return value->SetEnumerationValue(new_value); + } + return false; +} + + +OptionValueFileSpec * +OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpec (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const +{ + const Property *property = GetPropertyAtIndex (exe_ctx, false, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + return value->GetAsFileSpec(); + } + return NULL; +} + + +FileSpec +OptionValueProperties::GetPropertyAtIndexAsFileSpec (const ExecutionContext *exe_ctx, uint32_t idx) const +{ + const Property *property = GetPropertyAtIndex (exe_ctx, false, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + return value->GetFileSpecValue(); + } + return FileSpec(); +} + + +bool +OptionValueProperties::SetPropertyAtIndexAsFileSpec (const ExecutionContext *exe_ctx, uint32_t idx, const FileSpec &new_file_spec) +{ + const Property *property = GetPropertyAtIndex (exe_ctx, true, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + return value->SetFileSpecValue(new_file_spec); + } + return false; +} + +const RegularExpression * +OptionValueProperties::GetPropertyAtIndexAsOptionValueRegex (const ExecutionContext *exe_ctx, uint32_t idx) const +{ + const Property *property = GetPropertyAtIndex (exe_ctx, false, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + return value->GetRegexValue(); + } + return NULL; +} + +OptionValueSInt64 * +OptionValueProperties::GetPropertyAtIndexAsOptionValueSInt64 (const ExecutionContext *exe_ctx, uint32_t idx) const +{ + const Property *property = GetPropertyAtIndex (exe_ctx, false, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + return value->GetAsSInt64(); + } + return NULL; +} + +int64_t +OptionValueProperties::GetPropertyAtIndexAsSInt64 (const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const +{ + const Property *property = GetPropertyAtIndex (exe_ctx, false, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + return value->GetSInt64Value(fail_value); + } + return fail_value; +} + +bool +OptionValueProperties::SetPropertyAtIndexAsSInt64 (const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value) +{ + const Property *property = GetPropertyAtIndex (exe_ctx, true, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + return value->SetSInt64Value(new_value); + } + return false; +} + +const char * +OptionValueProperties::GetPropertyAtIndexAsString (const ExecutionContext *exe_ctx, uint32_t idx, const char *fail_value) const +{ + const Property *property = GetPropertyAtIndex (exe_ctx, false, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + return value->GetStringValue(fail_value); + } + return fail_value; +} + +bool +OptionValueProperties::SetPropertyAtIndexAsString (const ExecutionContext *exe_ctx, uint32_t idx, const char *new_value) +{ + const Property *property = GetPropertyAtIndex (exe_ctx, true, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + return value->SetStringValue(new_value); + } + return false; +} + +OptionValueString * +OptionValueProperties::GetPropertyAtIndexAsOptionValueString (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const +{ + OptionValueSP value_sp(GetPropertyValueAtIndex (exe_ctx, will_modify, idx)); + if (value_sp) + return value_sp->GetAsString(); + return NULL; +} + + +uint64_t +OptionValueProperties::GetPropertyAtIndexAsUInt64 (const ExecutionContext *exe_ctx, uint32_t idx, uint64_t fail_value) const +{ + const Property *property = GetPropertyAtIndex (exe_ctx, false, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + return value->GetUInt64Value(fail_value); + } + return fail_value; +} + +bool +OptionValueProperties::SetPropertyAtIndexAsUInt64 (const ExecutionContext *exe_ctx, uint32_t idx, uint64_t new_value) +{ + const Property *property = GetPropertyAtIndex (exe_ctx, true, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + return value->SetUInt64Value(new_value); + } + return false; +} + +bool +OptionValueProperties::Clear () +{ + const size_t num_properties = m_properties.size(); + for (size_t i=0; i<num_properties; ++i) + m_properties[i].GetValue()->Clear(); + return true; +} + + +Error +OptionValueProperties::SetValueFromCString (const char *value, VarSetOperationType op) +{ + Error error; + +// Args args(value_cstr); +// const size_t argc = args.GetArgumentCount(); + switch (op) + { + case eVarSetOperationClear: + Clear (); + break; + + case eVarSetOperationReplace: + case eVarSetOperationAssign: + case eVarSetOperationRemove: + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + case eVarSetOperationAppend: + case eVarSetOperationInvalid: + error = OptionValue::SetValueFromCString (value, op); + break; + } + + return error; +} + +void +OptionValueProperties::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) +{ + const size_t num_properties = m_properties.size(); + for (size_t i=0; i<num_properties; ++i) + { + const Property *property = GetPropertyAtIndex(exe_ctx, false, i); + if (property) + { + OptionValue *option_value = property->GetValue().get(); + assert (option_value); + const bool transparent_value = option_value->ValueIsTransparent (); + property->Dump (exe_ctx, + strm, + dump_mask); + if (!transparent_value) + strm.EOL(); + } + } +} + +Error +OptionValueProperties::DumpPropertyValue (const ExecutionContext *exe_ctx, + Stream &strm, + const char *property_path, + uint32_t dump_mask) +{ + Error error; + const bool will_modify = false; + lldb::OptionValueSP value_sp (GetSubValue (exe_ctx, property_path, will_modify, error)); + if (value_sp) + { + if (!value_sp->ValueIsTransparent ()) + { + if (dump_mask & eDumpOptionName) + strm.PutCString (property_path); + if (dump_mask & ~eDumpOptionName) + strm.PutChar (' '); + } + value_sp->DumpValue (exe_ctx, strm, dump_mask); + } + return error; +} + +lldb::OptionValueSP +OptionValueProperties::DeepCopy () const +{ + assert(!"this shouldn't happen"); +} + +const Property * +OptionValueProperties::GetPropertyAtPath (const ExecutionContext *exe_ctx, + bool will_modify, + const char *name) const +{ + const Property *property = NULL; + if (name && name[0]) + { + const char *sub_name = NULL; + ConstString key; + size_t key_len = ::strcspn (name, ".[{"); + + if (name[key_len]) + { + key.SetCStringWithLength (name, key_len); + sub_name = name + key_len; + } + else + key.SetCString (name); + + property = GetProperty (exe_ctx, will_modify, key); + if (sub_name && property) + { + if (sub_name[0] == '.') + { + OptionValueProperties *sub_properties = property->GetValue()->GetAsProperties(); + if (sub_properties) + return sub_properties->GetPropertyAtPath(exe_ctx, will_modify, sub_name + 1); + } + property = NULL; + } + } + return property; +} + +void +OptionValueProperties::DumpAllDescriptions (CommandInterpreter &interpreter, + Stream &strm) const +{ + size_t max_name_len = 0; + const size_t num_properties = m_properties.size(); + for (size_t i=0; i<num_properties; ++i) + { + const Property *property = ProtectedGetPropertyAtIndex(i); + if (property) + max_name_len = std::max<size_t>(property->GetName().GetLength(), max_name_len); + } + for (size_t i=0; i<num_properties; ++i) + { + const Property *property = ProtectedGetPropertyAtIndex(i); + if (property) + property->DumpDescription (interpreter, strm, max_name_len, false); + } +} + +void +OptionValueProperties::Apropos (const char *keyword, std::vector<const Property *> &matching_properties) const +{ + const size_t num_properties = m_properties.size(); + StreamString strm; + for (size_t i=0; i<num_properties; ++i) + { + const Property *property = ProtectedGetPropertyAtIndex(i); + if (property) + { + const OptionValueProperties *properties = property->GetValue()->GetAsProperties(); + if (properties) + { + properties->Apropos (keyword, matching_properties); + } + else + { + bool match = false; + const char *name = property->GetName().GetCString(); + if (name && ::strcasestr(name, keyword)) + match = true; + else + { + const char *desc = property->GetDescription(); + if (desc && ::strcasestr(desc, keyword)) + match = true; + } + if (match) + { + matching_properties.push_back (property); + } + } + } + } +} + +lldb::OptionValuePropertiesSP +OptionValueProperties::GetSubProperty (const ExecutionContext *exe_ctx, + const ConstString &name) +{ + lldb::OptionValueSP option_value_sp(GetValueForKey(exe_ctx, name, false)); + if (option_value_sp) + { + OptionValueProperties *ov_properties = option_value_sp->GetAsProperties (); + if (ov_properties) + return ov_properties->shared_from_this(); + } + return lldb::OptionValuePropertiesSP(); +} + + + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueRegex.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueRegex.cpp new file mode 100644 index 0000000..f1ba0ed --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueRegex.cpp @@ -0,0 +1,86 @@ +//===-- OptionValueRegex.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/OptionValueRegex.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Stream.h" + +using namespace lldb; +using namespace lldb_private; + +void +OptionValueRegex::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) +{ + if (dump_mask & eDumpOptionType) + strm.Printf ("(%s)", GetTypeAsCString ()); + if (dump_mask & eDumpOptionValue) + { + if (dump_mask & eDumpOptionType) + strm.PutCString (" = "); + if (m_regex.IsValid()) + { + const char *regex_text = m_regex.GetText(); + if (regex_text && regex_text[0]) + strm.Printf ("%s", regex_text); + } + else + { + + } + } +} + +Error +OptionValueRegex::SetValueFromCString (const char *value_cstr, + VarSetOperationType op) +{ + Error error; + switch (op) + { + case eVarSetOperationInvalid: + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + case eVarSetOperationRemove: + case eVarSetOperationAppend: + error = OptionValue::SetValueFromCString (value_cstr, op); + break; + + case eVarSetOperationClear: + Clear(); + break; + + case eVarSetOperationReplace: + case eVarSetOperationAssign: + if (m_regex.Compile (value_cstr, m_regex.GetCompileFlags())) + { + m_value_was_set = true; + } + else + { + char regex_error[1024]; + if (m_regex.GetErrorAsCString(regex_error, sizeof(regex_error))) + error.SetErrorString (regex_error); + else + error.SetErrorStringWithFormat ("regex error %u", m_regex.GetErrorCode()); + } + break; + } + return error; +} + + +lldb::OptionValueSP +OptionValueRegex::DeepCopy () const +{ + return OptionValueSP(new OptionValueRegex(m_regex.GetText(), m_regex.GetCompileFlags())); +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueSInt64.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueSInt64.cpp new file mode 100644 index 0000000..04bf930 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueSInt64.cpp @@ -0,0 +1,89 @@ +//===-- OptionValueSInt64.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/OptionValueSInt64.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Stream.h" +#include "lldb/Interpreter/Args.h" + +using namespace lldb; +using namespace lldb_private; + +void +OptionValueSInt64::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) +{ + //printf ("%p: DumpValue (exe_ctx=%p, strm, mask) m_current_value = %" PRIi64 "\n", this, exe_ctx, m_current_value); + if (dump_mask & eDumpOptionType) + strm.Printf ("(%s)", GetTypeAsCString ()); +// if (dump_mask & eDumpOptionName) +// DumpQualifiedName (strm); + if (dump_mask & eDumpOptionValue) + { + if (dump_mask & eDumpOptionType) + strm.PutCString (" = "); + strm.Printf ("%" PRIi64, m_current_value); + } +} + +Error +OptionValueSInt64::SetValueFromCString (const char *value_cstr, VarSetOperationType op) +{ + //printf ("%p: SetValueFromCString (s=\"%s\", op=%i)\n", this, value_cstr, op); + Error error; + switch (op) + { + case eVarSetOperationClear: + Clear(); + break; + + case eVarSetOperationReplace: + case eVarSetOperationAssign: + { + bool success = false; + int64_t value = Args::StringToSInt64 (value_cstr, 0, 0, &success); + if (success) + { + if (value >= m_min_value && value <= m_max_value) + { + m_value_was_set = true; + m_current_value = value; + } + else + error.SetErrorStringWithFormat ("%" PRIi64 " is out of range, valid values must be between %" PRIi64 " and %" PRIi64 ".", + value, + m_min_value, + m_max_value); + } + else + { + error.SetErrorStringWithFormat ("invalid int64_t string value: '%s'", value_cstr); + } + } + break; + + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + case eVarSetOperationRemove: + case eVarSetOperationAppend: + case eVarSetOperationInvalid: + error = OptionValue::SetValueFromCString (value_cstr, op); + break; + } + return error; +} + +lldb::OptionValueSP +OptionValueSInt64::DeepCopy () const +{ + return OptionValueSP(new OptionValueSInt64(*this)); +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueString.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueString.cpp new file mode 100644 index 0000000..df047bd --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueString.cpp @@ -0,0 +1,186 @@ +//===-- OptionValueString.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/OptionValueString.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Stream.h" +#include "lldb/Interpreter/Args.h" + +using namespace lldb; +using namespace lldb_private; + +void +OptionValueString::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) +{ + if (dump_mask & eDumpOptionType) + strm.Printf ("(%s)", GetTypeAsCString ()); + if (dump_mask & eDumpOptionValue) + { + if (dump_mask & eDumpOptionType) + strm.PutCString (" = "); + if (!m_current_value.empty() || m_value_was_set) + { + if (m_options.Test (eOptionEncodeCharacterEscapeSequences)) + { + std::string expanded_escape_value; + Args::ExpandEscapedCharacters(m_current_value.c_str(), expanded_escape_value); + if (dump_mask & eDumpOptionRaw) + strm.Printf ("%s", expanded_escape_value.c_str()); + else + strm.Printf ("\"%s\"", expanded_escape_value.c_str()); + } + else + { + if (dump_mask & eDumpOptionRaw) + strm.Printf ("%s", m_current_value.c_str()); + else + strm.Printf ("\"%s\"", m_current_value.c_str()); + } + } + } +} + +Error +OptionValueString::SetValueFromCString (const char *value_cstr, + VarSetOperationType op) +{ + Error error; + + std::string value_str_no_quotes; + if (value_cstr) + { + switch (value_cstr[0]) + { + case '"': + case '\'': + { + size_t len = strlen(value_cstr); + if (len <= 1 || value_cstr[len-1] != value_cstr[0]) + { + error.SetErrorString("mismatched quotes"); + return error; + } + value_str_no_quotes.assign (value_cstr + 1, len - 2); + value_cstr = value_str_no_quotes.c_str(); + } + break; + } + } + + switch (op) + { + case eVarSetOperationInvalid: + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + case eVarSetOperationRemove: + if (m_validator) + { + error = m_validator(value_cstr,m_validator_baton); + if (error.Fail()) + return error; + } + error = OptionValue::SetValueFromCString (value_cstr, op); + break; + + case eVarSetOperationAppend: + { + std::string new_value(m_current_value); + if (value_cstr && value_cstr[0]) + { + if (m_options.Test (eOptionEncodeCharacterEscapeSequences)) + { + std::string str; + Args::EncodeEscapeSequences (value_cstr, str); + new_value.append(str); + } + else + new_value.append(value_cstr); + } + if (m_validator) + { + error = m_validator(new_value.c_str(),m_validator_baton); + if (error.Fail()) + return error; + } + m_current_value.assign(new_value); + } + break; + + case eVarSetOperationClear: + Clear (); + break; + + case eVarSetOperationReplace: + case eVarSetOperationAssign: + if (m_validator) + { + error = m_validator(value_cstr,m_validator_baton); + if (error.Fail()) + return error; + } + m_value_was_set = true; + if (m_options.Test (eOptionEncodeCharacterEscapeSequences)) + { + Args::EncodeEscapeSequences (value_cstr, m_current_value); + } + else + { + SetCurrentValue (value_cstr); + } + break; + } + return error; +} + + +lldb::OptionValueSP +OptionValueString::DeepCopy () const +{ + return OptionValueSP(new OptionValueString(*this)); +} + +Error +OptionValueString::SetCurrentValue (const char *value) +{ + if (m_validator) + { + Error error(m_validator(value,m_validator_baton)); + if (error.Fail()) + return error; + } + if (value && value[0]) + m_current_value.assign (value); + else + m_current_value.clear(); + return Error(); +} + +Error +OptionValueString::AppendToCurrentValue (const char *value) +{ + if (value && value[0]) + { + if (m_validator) + { + std::string new_value(m_current_value); + new_value.append(value); + Error error(m_validator(value,m_validator_baton)); + if (error.Fail()) + return error; + m_current_value.assign(new_value); + } + else + m_current_value.append (value); + } + return Error(); +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueUInt64.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueUInt64.cpp new file mode 100644 index 0000000..56b3a1c --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueUInt64.cpp @@ -0,0 +1,89 @@ +//===-- OptionValueUInt64.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/OptionValueUInt64.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Stream.h" +#include "lldb/Interpreter/Args.h" + +using namespace lldb; +using namespace lldb_private; + +lldb::OptionValueSP +OptionValueUInt64::Create (const char *value_cstr, Error &error) +{ + lldb::OptionValueSP value_sp (new OptionValueUInt64()); + error = value_sp->SetValueFromCString (value_cstr); + if (error.Fail()) + value_sp.reset(); + return value_sp; +} + + +void +OptionValueUInt64::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) +{ + if (dump_mask & eDumpOptionType) + strm.Printf ("(%s)", GetTypeAsCString ()); + if (dump_mask & eDumpOptionValue) + { + if (dump_mask & eDumpOptionType) + strm.PutCString (" = "); + strm.Printf ("%" PRIu64, m_current_value); + } +} + +Error +OptionValueUInt64::SetValueFromCString (const char *value_cstr, VarSetOperationType op) +{ + Error error; + switch (op) + { + case eVarSetOperationClear: + Clear (); + break; + + case eVarSetOperationReplace: + case eVarSetOperationAssign: + { + bool success = false; + uint64_t value = Args::StringToUInt64 (value_cstr, 0, 0, &success); + if (success) + { + m_value_was_set = true; + m_current_value = value; + } + else + { + error.SetErrorStringWithFormat ("invalid uint64_t string value: '%s'", value_cstr); + } + } + break; + + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + case eVarSetOperationRemove: + case eVarSetOperationAppend: + case eVarSetOperationInvalid: + error = OptionValue::SetValueFromCString (value_cstr, op); + break; + } + return error; +} + +lldb::OptionValueSP +OptionValueUInt64::DeepCopy () const +{ + return OptionValueSP(new OptionValueUInt64(*this)); +} + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueUUID.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueUUID.cpp new file mode 100644 index 0000000..340f1e5 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueUUID.cpp @@ -0,0 +1,123 @@ +//===-- OptionValueUUID.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/lldb-python.h" + +#include "lldb/Interpreter/OptionValueUUID.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Module.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StringList.h" +#include "lldb/Interpreter/CommandInterpreter.h" + +using namespace lldb; +using namespace lldb_private; + +void +OptionValueUUID::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) +{ + if (dump_mask & eDumpOptionType) + strm.Printf ("(%s)", GetTypeAsCString ()); + if (dump_mask & eDumpOptionValue) + { + if (dump_mask & eDumpOptionType) + strm.PutCString (" = "); + m_uuid.Dump (&strm); + } +} + +Error +OptionValueUUID::SetValueFromCString (const char *value_cstr, + VarSetOperationType op) +{ + Error error; + switch (op) + { + case eVarSetOperationClear: + Clear(); + break; + + case eVarSetOperationReplace: + case eVarSetOperationAssign: + { + if (m_uuid.SetFromCString(value_cstr) == 0) + error.SetErrorStringWithFormat ("invalid uuid string value '%s'", value_cstr); + else + m_value_was_set = true; + } + break; + + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + case eVarSetOperationRemove: + case eVarSetOperationAppend: + case eVarSetOperationInvalid: + error = OptionValue::SetValueFromCString (value_cstr, op); + break; + } + return error; +} + +lldb::OptionValueSP +OptionValueUUID::DeepCopy () const +{ + return OptionValueSP(new OptionValueUUID(*this)); +} + +size_t +OptionValueUUID::AutoComplete (CommandInterpreter &interpreter, + const char *s, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches) +{ + word_complete = false; + matches.Clear(); + ExecutionContext exe_ctx(interpreter.GetExecutionContext()); + Target *target = exe_ctx.GetTargetPtr(); + if (target) + { + const size_t num_modules = target->GetImages().GetSize(); + if (num_modules > 0) + { + UUID::ValueType uuid_bytes; + const size_t num_bytes_decoded = UUID::DecodeUUIDBytesFromCString(s, uuid_bytes, NULL); + for (size_t i=0; i<num_modules; ++i) + { + ModuleSP module_sp (target->GetImages().GetModuleAtIndex(i)); + if (module_sp) + { + const UUID &module_uuid = module_sp->GetUUID(); + if (module_uuid.IsValid()) + { + bool add_uuid = false; + if (num_bytes_decoded == 0) + add_uuid = true; + else + add_uuid = ::memcmp(module_uuid.GetBytes(), uuid_bytes, num_bytes_decoded) == 0; + if (add_uuid) + { + std::string uuid_str; + uuid_str = module_uuid.GetAsString(); + if (!uuid_str.empty()) + matches.AppendString(uuid_str.c_str()); + } + } + } + } + } + } + return matches.GetSize(); +} + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/Options.cpp b/contrib/llvm/tools/lldb/source/Interpreter/Options.cpp new file mode 100644 index 0000000..293d753 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/Options.cpp @@ -0,0 +1,1077 @@ +//===-- Options.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/lldb-python.h" + +#include "lldb/Interpreter/Options.h" + +// C Includes +// C++ Includes +#include <algorithm> +#include <bitset> +#include <map> + +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/CommandCompletions.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// Options +//------------------------------------------------------------------------- +Options::Options (CommandInterpreter &interpreter) : + m_interpreter (interpreter), + m_getopt_table () +{ + BuildValidOptionSets(); +} + +Options::~Options () +{ +} + +void +Options::NotifyOptionParsingStarting () +{ + m_seen_options.clear(); + // Let the subclass reset its option values + OptionParsingStarting (); +} + +Error +Options::NotifyOptionParsingFinished () +{ + return OptionParsingFinished (); +} + +void +Options::OptionSeen (int option_idx) +{ + m_seen_options.insert (option_idx); +} + +// Returns true is set_a is a subset of set_b; Otherwise returns false. + +bool +Options::IsASubset (const OptionSet& set_a, const OptionSet& set_b) +{ + bool is_a_subset = true; + OptionSet::const_iterator pos_a; + OptionSet::const_iterator pos_b; + + // set_a is a subset of set_b if every member of set_a is also a member of set_b + + for (pos_a = set_a.begin(); pos_a != set_a.end() && is_a_subset; ++pos_a) + { + pos_b = set_b.find(*pos_a); + if (pos_b == set_b.end()) + is_a_subset = false; + } + + return is_a_subset; +} + +// Returns the set difference set_a - set_b, i.e. { x | ElementOf (x, set_a) && !ElementOf (x, set_b) } + +size_t +Options::OptionsSetDiff (const OptionSet& set_a, const OptionSet& set_b, OptionSet& diffs) +{ + size_t num_diffs = 0; + OptionSet::const_iterator pos_a; + OptionSet::const_iterator pos_b; + + for (pos_a = set_a.begin(); pos_a != set_a.end(); ++pos_a) + { + pos_b = set_b.find(*pos_a); + if (pos_b == set_b.end()) + { + ++num_diffs; + diffs.insert(*pos_a); + } + } + + return num_diffs; +} + +// Returns the union of set_a and set_b. Does not put duplicate members into the union. + +void +Options::OptionsSetUnion (const OptionSet &set_a, const OptionSet &set_b, OptionSet &union_set) +{ + OptionSet::const_iterator pos; + OptionSet::iterator pos_union; + + // Put all the elements of set_a into the union. + + for (pos = set_a.begin(); pos != set_a.end(); ++pos) + union_set.insert(*pos); + + // Put all the elements of set_b that are not already there into the union. + for (pos = set_b.begin(); pos != set_b.end(); ++pos) + { + pos_union = union_set.find(*pos); + if (pos_union == union_set.end()) + union_set.insert(*pos); + } +} + +bool +Options::VerifyOptions (CommandReturnObject &result) +{ + bool options_are_valid = false; + + int num_levels = GetRequiredOptions().size(); + if (num_levels) + { + for (int i = 0; i < num_levels && !options_are_valid; ++i) + { + // This is the correct set of options if: 1). m_seen_options contains all of m_required_options[i] + // (i.e. all the required options at this level are a subset of m_seen_options); AND + // 2). { m_seen_options - m_required_options[i] is a subset of m_options_options[i] (i.e. all the rest of + // m_seen_options are in the set of optional options at this level. + + // Check to see if all of m_required_options[i] are a subset of m_seen_options + if (IsASubset (GetRequiredOptions()[i], m_seen_options)) + { + // Construct the set difference: remaining_options = {m_seen_options} - {m_required_options[i]} + OptionSet remaining_options; + OptionsSetDiff (m_seen_options, GetRequiredOptions()[i], remaining_options); + // Check to see if remaining_options is a subset of m_optional_options[i] + if (IsASubset (remaining_options, GetOptionalOptions()[i])) + options_are_valid = true; + } + } + } + else + { + options_are_valid = true; + } + + if (options_are_valid) + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendError ("invalid combination of options for the given command"); + result.SetStatus (eReturnStatusFailed); + } + + return options_are_valid; +} + +// This is called in the Options constructor, though we could call it lazily if that ends up being +// a performance problem. + +void +Options::BuildValidOptionSets () +{ + // Check to see if we already did this. + if (m_required_options.size() != 0) + return; + + // Check to see if there are any options. + int num_options = NumCommandOptions (); + if (num_options == 0) + return; + + const OptionDefinition *opt_defs = GetDefinitions(); + m_required_options.resize(1); + m_optional_options.resize(1); + + // First count the number of option sets we've got. Ignore LLDB_ALL_OPTION_SETS... + + uint32_t num_option_sets = 0; + + for (int i = 0; i < num_options; i++) + { + uint32_t this_usage_mask = opt_defs[i].usage_mask; + if (this_usage_mask == LLDB_OPT_SET_ALL) + { + if (num_option_sets == 0) + num_option_sets = 1; + } + else + { + for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++) + { + if (this_usage_mask & (1 << j)) + { + if (num_option_sets <= j) + num_option_sets = j + 1; + } + } + } + } + + if (num_option_sets > 0) + { + m_required_options.resize(num_option_sets); + m_optional_options.resize(num_option_sets); + + for (int i = 0; i < num_options; ++i) + { + for (uint32_t j = 0; j < num_option_sets; j++) + { + if (opt_defs[i].usage_mask & 1 << j) + { + if (opt_defs[i].required) + m_required_options[j].insert(opt_defs[i].short_option); + else + m_optional_options[j].insert(opt_defs[i].short_option); + } + } + } + } +} + +uint32_t +Options::NumCommandOptions () +{ + const OptionDefinition *opt_defs = GetDefinitions (); + if (opt_defs == NULL) + return 0; + + int i = 0; + + if (opt_defs != NULL) + { + while (opt_defs[i].long_option != NULL) + ++i; + } + + return i; +} + +struct option * +Options::GetLongOptions () +{ + // Check to see if this has already been done. + if (m_getopt_table.empty()) + { + // Check to see if there are any options. + const uint32_t num_options = NumCommandOptions(); + if (num_options == 0) + return NULL; + + uint32_t i; + const OptionDefinition *opt_defs = GetDefinitions(); + + std::map<int, uint32_t> option_seen; + + m_getopt_table.resize(num_options + 1); + for (i = 0; i < num_options; ++i) + { + 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].flag = NULL; + m_getopt_table[i].val = short_opt; + + if (option_seen.find(short_opt) == option_seen.end()) + { + option_seen[short_opt] = i; + } + else if (short_opt) + { + m_getopt_table[i].val = 0; + std::map<int, uint32_t>::const_iterator pos = option_seen.find(short_opt); + StreamString strm; + if (isprint8(short_opt)) + Host::SystemLog (Host::eSystemLogError, "option[%u] --%s has a short option -%c that conflicts with option[%u] --%s, short option won't be used for --%s\n", + i, + opt_defs[i].long_option, + short_opt, + pos->second, + m_getopt_table[pos->second].name, + 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", + i, + opt_defs[i].long_option, + short_opt, + pos->second, + m_getopt_table[pos->second].name, + opt_defs[i].long_option); + } + } + + //getopt_long_only requires a NULL final entry in the table: + + m_getopt_table[i].name = NULL; + m_getopt_table[i].has_arg = 0; + m_getopt_table[i].flag = NULL; + m_getopt_table[i].val = 0; + } + + if (m_getopt_table.empty()) + return NULL; + + return &m_getopt_table.front(); +} + + +// This function takes INDENT, which tells how many spaces to output at the front of each line; SPACES, which is +// a string containing 80 spaces; and TEXT, which is the text that is to be output. It outputs the text, on +// multiple lines if necessary, to RESULT, with INDENT spaces at the front of each line. It breaks lines on spaces, +// tabs or newlines, shortening the line if necessary to not break in the middle of a word. It assumes that each +// output line should contain a maximum of OUTPUT_MAX_COLUMNS characters. + + +void +Options::OutputFormattedUsageText +( + Stream &strm, + const char *text, + uint32_t output_max_columns +) +{ + int len = strlen (text); + + // Will it all fit on one line? + + if ((len + strm.GetIndentLevel()) < output_max_columns) + { + // Output it as a single line. + strm.Indent (text); + strm.EOL(); + } + else + { + // We need to break it up into multiple lines. + + int text_width = output_max_columns - strm.GetIndentLevel() - 1; + int start = 0; + int end = start; + int final_end = strlen (text); + 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] == ' ')) + start++; + + end = start + text_width; + if (end > final_end) + end = final_end; + else + { + // 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') + end--; + } + + sub_len = end - start; + if (start != 0) + strm.EOL(); + strm.Indent(); + assert (start < final_end); + assert (start + sub_len <= final_end); + strm.Write(text + start, sub_len); + start = end + 1; + } + strm.EOL(); + } +} + +bool +Options::SupportsLongOption (const char *long_option) +{ + if (long_option && long_option[0]) + { + const OptionDefinition *opt_defs = GetDefinitions (); + if (opt_defs) + { + const char *long_option_name = long_option; + if (long_option[0] == '-' && long_option[1] == '-') + long_option_name += 2; + + for (uint32_t i = 0; opt_defs[i].long_option; ++i) + { + if (strcmp(opt_defs[i].long_option, long_option_name) == 0) + return true; + } + } + } + return false; +} + +enum OptionDisplayType +{ + eDisplayBestOption, + eDisplayShortOption, + eDisplayLongOption +}; + +static bool +PrintOption (const OptionDefinition &opt_def, + OptionDisplayType display_type, + const char *header, + const char *footer, + bool show_optional, + Stream &strm) +{ + const bool has_short_option = isprint8(opt_def.short_option) != 0; + + if (display_type == eDisplayShortOption && !has_short_option) + return false; + + if (header && header[0]) + strm.PutCString(header); + + if (show_optional && !opt_def.required) + strm.PutChar('['); + const bool show_short_option = has_short_option && display_type != eDisplayLongOption; + if (show_short_option) + strm.Printf ("-%c", opt_def.short_option); + else + strm.Printf ("--%s", opt_def.long_option); + switch (opt_def.option_has_arg) + { + case no_argument: + break; + case required_argument: + strm.Printf (" <%s>", CommandObject::GetArgumentName (opt_def.argument_type)); + break; + + case optional_argument: + strm.Printf ("%s[<%s>]", + show_short_option ? "" : "=", + CommandObject::GetArgumentName (opt_def.argument_type)); + break; + } + if (show_optional && !opt_def.required) + strm.PutChar(']'); + if (footer && footer[0]) + strm.PutCString(footer); + return true; +} + +void +Options::GenerateOptionUsage +( + Stream &strm, + CommandObject *cmd +) +{ + const uint32_t screen_width = m_interpreter.GetDebugger().GetTerminalWidth(); + + const OptionDefinition *opt_defs = GetDefinitions(); + const uint32_t save_indent_level = strm.GetIndentLevel(); + const char *name; + + StreamString arguments_str; + + if (cmd) + { + name = cmd->GetCommandName(); + cmd->GetFormattedCommandArguments (arguments_str); + } + else + name = ""; + + strm.PutCString ("\nCommand Options Usage:\n"); + + strm.IndentMore(2); + + // First, show each usage level set of options, e.g. <cmd> [options-for-level-0] + // <cmd> [options-for-level-1] + // etc. + + const uint32_t num_options = NumCommandOptions(); + if (num_options == 0) + return; + + uint32_t num_option_sets = GetRequiredOptions().size(); + + uint32_t i; + + for (uint32_t opt_set = 0; opt_set < num_option_sets; ++opt_set) + { + uint32_t opt_set_mask; + + opt_set_mask = 1 << opt_set; + if (opt_set > 0) + strm.Printf ("\n"); + strm.Indent (name); + + // Different option sets may require different args. + StreamString args_str; + if (cmd) + cmd->GetFormattedCommandArguments(args_str, opt_set_mask); + + // First go through and print all options that take no arguments as + // a single string. If a command has "-a" "-b" and "-c", this will show + // up as [-abc] + + std::set<int> options; + std::set<int>::const_iterator options_pos, options_end; + for (i = 0; i < num_options; ++i) + { + if (opt_defs[i].usage_mask & opt_set_mask && isprint8(opt_defs[i].short_option)) + { + // Add current option to the end of out_stream. + + if (opt_defs[i].required == true && + opt_defs[i].option_has_arg == no_argument) + { + options.insert (opt_defs[i].short_option); + } + } + } + + if (options.empty() == false) + { + // We have some required options with no arguments + strm.PutCString(" -"); + for (i=0; i<2; ++i) + for (options_pos = options.begin(), options_end = options.end(); + options_pos != options_end; + ++options_pos) + { + if (i==0 && ::islower (*options_pos)) + continue; + if (i==1 && ::isupper (*options_pos)) + continue; + strm << (char)*options_pos; + } + } + + for (i = 0, options.clear(); i < num_options; ++i) + { + if (opt_defs[i].usage_mask & opt_set_mask && isprint8(opt_defs[i].short_option)) + { + // Add current option to the end of out_stream. + + if (opt_defs[i].required == false && + opt_defs[i].option_has_arg == no_argument) + { + options.insert (opt_defs[i].short_option); + } + } + } + + if (options.empty() == false) + { + // We have some required options with no arguments + strm.PutCString(" [-"); + for (i=0; i<2; ++i) + for (options_pos = options.begin(), options_end = options.end(); + options_pos != options_end; + ++options_pos) + { + if (i==0 && ::islower (*options_pos)) + continue; + if (i==1 && ::isupper (*options_pos)) + continue; + strm << (char)*options_pos; + } + strm.PutChar(']'); + } + + // First go through and print the required options (list them up front). + + for (i = 0; i < num_options; ++i) + { + if (opt_defs[i].usage_mask & opt_set_mask && isprint8(opt_defs[i].short_option)) + { + if (opt_defs[i].required && opt_defs[i].option_has_arg != no_argument) + PrintOption (opt_defs[i], eDisplayBestOption, " ", NULL, true, strm); + } + } + + // Now go through again, and this time only print the optional options. + + for (i = 0; i < num_options; ++i) + { + if (opt_defs[i].usage_mask & opt_set_mask) + { + // Add current option to the end of out_stream. + + if (!opt_defs[i].required && opt_defs[i].option_has_arg != no_argument) + PrintOption (opt_defs[i], eDisplayBestOption, " ", NULL, true, strm); + } + } + + if (args_str.GetSize() > 0) + { + if (cmd->WantsRawCommandString()) + strm.Printf(" --"); + + strm.Printf (" %s", args_str.GetData()); + } + } + + if (cmd && + cmd->WantsRawCommandString() && + arguments_str.GetSize() > 0) + { + strm.PutChar('\n'); + strm.Indent(name); + strm.Printf(" %s", arguments_str.GetData()); + } + + 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> ) + // help text + + // This variable is used to keep track of which options' info we've printed out, because some options can be in + // more than one usage level, but we only want to print the long form of its information once. + + std::multimap<int, uint32_t> options_seen; + strm.IndentMore (5); + + // Put the unique command options in a vector & sort it, so we can output them alphabetically (by short_option) + // when writing out detailed help for each option. + + for (i = 0; i < num_options; ++i) + options_seen.insert(std::make_pair(opt_defs[i].short_option, i)); + + // Go through the unique'd and alphabetically sorted vector of options, find the table entry for each option + // and write out the detailed help information for that option. + + bool first_option_printed = false;; + + for (auto pos : options_seen) + { + i = pos.second; + //Print out the help information for this option. + + // Put a newline separation between arguments + if (first_option_printed) + strm.EOL(); + else + first_option_printed = true; + + CommandArgumentType arg_type = opt_defs[i].argument_type; + + StreamString arg_name_str; + arg_name_str.Printf ("<%s>", CommandObject::GetArgumentName (arg_type)); + + strm.Indent (); + if (opt_defs[i].short_option && isprint8(opt_defs[i].short_option)) + { + PrintOption (opt_defs[i], eDisplayShortOption, NULL, NULL, false, strm); + PrintOption (opt_defs[i], eDisplayLongOption, " ( ", " )", false, strm); + } + else + { + // Short option is not printable, just print long option + PrintOption (opt_defs[i], eDisplayLongOption, NULL, NULL, false, strm); + } + strm.EOL(); + + strm.IndentMore (5); + + if (opt_defs[i].usage_text) + OutputFormattedUsageText (strm, + opt_defs[i].usage_text, + screen_width); + if (opt_defs[i].enum_values != NULL) + { + strm.Indent (); + strm.Printf("Values: "); + for (int k = 0; opt_defs[i].enum_values[k].string_value != NULL; k++) + { + if (k == 0) + strm.Printf("%s", opt_defs[i].enum_values[k].string_value); + else + strm.Printf(" | %s", opt_defs[i].enum_values[k].string_value); + } + strm.EOL(); + } + strm.IndentLess (5); + } + + // Restore the indent level + strm.SetIndentLevel (save_indent_level); +} + +// This function is called when we have been given a potentially incomplete set of +// options, such as when an alias has been defined (more options might be added at +// at the time the alias is invoked). We need to verify that the options in the set +// m_seen_options are all part of a set that may be used together, but m_seen_options +// may be missing some of the "required" options. + +bool +Options::VerifyPartialOptions (CommandReturnObject &result) +{ + bool options_are_valid = false; + + int num_levels = GetRequiredOptions().size(); + if (num_levels) + { + for (int i = 0; i < num_levels && !options_are_valid; ++i) + { + // In this case we are treating all options as optional rather than required. + // Therefore a set of options is correct if m_seen_options is a subset of the + // union of m_required_options and m_optional_options. + OptionSet union_set; + OptionsSetUnion (GetRequiredOptions()[i], GetOptionalOptions()[i], union_set); + if (IsASubset (m_seen_options, union_set)) + options_are_valid = true; + } + } + + return options_are_valid; +} + +bool +Options::HandleOptionCompletion +( + Args &input, + OptionElementVector &opt_element_vector, + int cursor_index, + int char_pos, + int match_start_point, + int max_return_elements, + bool &word_complete, + lldb_private::StringList &matches +) +{ + word_complete = true; + + // For now we just scan the completions to see if the cursor position is in + // an option or its argument. Otherwise we'll call HandleArgumentCompletion. + // In the future we can use completion to validate options as well if we want. + + const OptionDefinition *opt_defs = GetDefinitions(); + + std::string cur_opt_std_str (input.GetArgumentAtIndex(cursor_index)); + cur_opt_std_str.erase(char_pos); + const char *cur_opt_str = cur_opt_std_str.c_str(); + + for (size_t i = 0; i < opt_element_vector.size(); i++) + { + int opt_pos = opt_element_vector[i].opt_pos; + int opt_arg_pos = opt_element_vector[i].opt_arg_pos; + int opt_defs_index = opt_element_vector[i].opt_defs_index; + if (opt_pos == cursor_index) + { + // We're completing the option itself. + + if (opt_defs_index == OptionArgElement::eBareDash) + { + // We're completing a bare dash. That means all options are open. + // FIXME: We should scan the other options provided and only complete options + // within the option group they belong to. + char opt_str[3] = {'-', 'a', '\0'}; + + for (int j = 0 ; opt_defs[j].short_option != 0 ; j++) + { + opt_str[1] = opt_defs[j].short_option; + matches.AppendString (opt_str); + } + return true; + } + else if (opt_defs_index == OptionArgElement::eBareDoubleDash) + { + std::string full_name ("--"); + for (int j = 0 ; opt_defs[j].short_option != 0 ; j++) + { + full_name.erase(full_name.begin() + 2, full_name.end()); + full_name.append (opt_defs[j].long_option); + matches.AppendString (full_name.c_str()); + } + return true; + } + else if (opt_defs_index != OptionArgElement::eUnrecognizedArg) + { + // We recognized it, if it an incomplete long option, complete it anyway (getopt_long_only is + // happy with shortest unique string, but it's still a nice thing to do.) Otherwise return + // The string so the upper level code will know this is a full match and add the " ". + if (cur_opt_str && strlen (cur_opt_str) > 2 + && cur_opt_str[0] == '-' && cur_opt_str[1] == '-' + && strcmp (opt_defs[opt_defs_index].long_option, cur_opt_str) != 0) + { + std::string full_name ("--"); + full_name.append (opt_defs[opt_defs_index].long_option); + matches.AppendString(full_name.c_str()); + return true; + } + else + { + matches.AppendString(input.GetArgumentAtIndex(cursor_index)); + return true; + } + } + else + { + // FIXME - not handling wrong options yet: + // Check to see if they are writing a long option & complete it. + // I think we will only get in here if the long option table has two elements + // that are not unique up to this point. getopt_long_only does shortest unique match + // for long options already. + + if (cur_opt_str && strlen (cur_opt_str) > 2 + && cur_opt_str[0] == '-' && cur_opt_str[1] == '-') + { + for (int j = 0 ; opt_defs[j].short_option != 0 ; j++) + { + if (strstr(opt_defs[j].long_option, cur_opt_str + 2) == opt_defs[j].long_option) + { + std::string full_name ("--"); + full_name.append (opt_defs[j].long_option); + // The options definitions table has duplicates because of the + // way the grouping information is stored, so only add once. + bool duplicate = false; + for (size_t k = 0; k < matches.GetSize(); k++) + { + if (matches.GetStringAtIndex(k) == full_name) + { + duplicate = true; + break; + } + } + if (!duplicate) + matches.AppendString(full_name.c_str()); + } + } + } + return true; + } + + + } + else if (opt_arg_pos == cursor_index) + { + // Okay the cursor is on the completion of an argument. + // See if it has a completion, otherwise return no matches. + + if (opt_defs_index != -1) + { + HandleOptionArgumentCompletion (input, + cursor_index, + strlen (input.GetArgumentAtIndex(cursor_index)), + opt_element_vector, + i, + match_start_point, + max_return_elements, + word_complete, + matches); + return true; + } + else + { + // No completion callback means no completions... + return true; + } + + } + else + { + // Not the last element, keep going. + continue; + } + } + return false; +} + +bool +Options::HandleOptionArgumentCompletion +( + Args &input, + int cursor_index, + int char_pos, + OptionElementVector &opt_element_vector, + int opt_element_index, + int match_start_point, + int max_return_elements, + bool &word_complete, + lldb_private::StringList &matches +) +{ + const OptionDefinition *opt_defs = GetDefinitions(); + std::unique_ptr<SearchFilter> filter_ap; + + int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos; + int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index; + + // See if this is an enumeration type option, and if so complete it here: + + OptionEnumValueElement *enum_values = opt_defs[opt_defs_index].enum_values; + if (enum_values != NULL) + { + bool return_value = false; + std::string match_string(input.GetArgumentAtIndex (opt_arg_pos), input.GetArgumentAtIndex (opt_arg_pos) + char_pos); + for (int i = 0; enum_values[i].string_value != NULL; i++) + { + if (strstr(enum_values[i].string_value, match_string.c_str()) == enum_values[i].string_value) + { + matches.AppendString (enum_values[i].string_value); + return_value = true; + } + } + return return_value; + } + + // If this is a source file or symbol type completion, and there is a + // -shlib option somewhere in the supplied arguments, then make a search filter + // for that shared library. + // FIXME: Do we want to also have an "OptionType" so we don't have to match string names? + + uint32_t completion_mask = opt_defs[opt_defs_index].completion_type; + + if (completion_mask == 0) + { + lldb::CommandArgumentType option_arg_type = opt_defs[opt_defs_index].argument_type; + if (option_arg_type != eArgTypeNone) + { + CommandObject::ArgumentTableEntry *arg_entry = CommandObject::FindArgumentDataByType (opt_defs[opt_defs_index].argument_type); + if (arg_entry) + completion_mask = arg_entry->completion_type; + } + } + + if (completion_mask & CommandCompletions::eSourceFileCompletion + || completion_mask & CommandCompletions::eSymbolCompletion) + { + for (size_t i = 0; i < opt_element_vector.size(); i++) + { + int cur_defs_index = opt_element_vector[i].opt_defs_index; + int cur_arg_pos = opt_element_vector[i].opt_arg_pos; + const char *cur_opt_name = opt_defs[cur_defs_index].long_option; + + // If this is the "shlib" option and there was an argument provided, + // restrict it to that shared library. + if (strcmp(cur_opt_name, "shlib") == 0 && cur_arg_pos != -1) + { + const char *module_name = input.GetArgumentAtIndex(cur_arg_pos); + if (module_name) + { + FileSpec module_spec(module_name, false); + lldb::TargetSP target_sp = m_interpreter.GetDebugger().GetSelectedTarget(); + // Search filters require a target... + if (target_sp) + filter_ap.reset (new SearchFilterByModule (target_sp, module_spec)); + } + break; + } + } + } + + return CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter, + completion_mask, + input.GetArgumentAtIndex (opt_arg_pos), + match_start_point, + max_return_elements, + filter_ap.get(), + word_complete, + matches); + +} + + +void +OptionGroupOptions::Append (OptionGroup* group) +{ + const OptionDefinition* group_option_defs = group->GetDefinitions (); + const uint32_t group_option_count = group->GetNumDefinitions(); + for (uint32_t i=0; i<group_option_count; ++i) + { + m_option_infos.push_back (OptionInfo (group, i)); + m_option_defs.push_back (group_option_defs[i]); + } +} + +void +OptionGroupOptions::Append (OptionGroup* group, + uint32_t src_mask, + uint32_t dst_mask) +{ + const OptionDefinition* group_option_defs = group->GetDefinitions (); + const uint32_t group_option_count = group->GetNumDefinitions(); + for (uint32_t i=0; i<group_option_count; ++i) + { + if (group_option_defs[i].usage_mask & src_mask) + { + m_option_infos.push_back (OptionInfo (group, i)); + m_option_defs.push_back (group_option_defs[i]); + m_option_defs.back().usage_mask = dst_mask; + } + } +} + +void +OptionGroupOptions::Finalize () +{ + m_did_finalize = true; + OptionDefinition empty_option_def = { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }; + m_option_defs.push_back (empty_option_def); +} + +Error +OptionGroupOptions::SetOptionValue (uint32_t option_idx, + const char *option_value) +{ + // After calling OptionGroupOptions::Append(...), you must finalize the groups + // by calling OptionGroupOptions::Finlize() + assert (m_did_finalize); + assert (m_option_infos.size() + 1 == m_option_defs.size()); + Error error; + if (option_idx < m_option_infos.size()) + { + error = m_option_infos[option_idx].option_group->SetOptionValue (m_interpreter, + m_option_infos[option_idx].option_index, + option_value); + + } + else + { + error.SetErrorString ("invalid option index"); // Shouldn't happen... + } + return error; +} + +void +OptionGroupOptions::OptionParsingStarting () +{ + std::set<OptionGroup*> group_set; + OptionInfos::iterator pos, end = m_option_infos.end(); + for (pos = m_option_infos.begin(); pos != end; ++pos) + { + OptionGroup* group = pos->option_group; + if (group_set.find(group) == group_set.end()) + { + group->OptionParsingStarting (m_interpreter); + group_set.insert(group); + } + } +} +Error +OptionGroupOptions::OptionParsingFinished () +{ + std::set<OptionGroup*> group_set; + Error error; + OptionInfos::iterator pos, end = m_option_infos.end(); + for (pos = m_option_infos.begin(); pos != end; ++pos) + { + OptionGroup* group = pos->option_group; + if (group_set.find(group) == group_set.end()) + { + error = group->OptionParsingFinished (m_interpreter); + group_set.insert(group); + if (error.Fail()) + return error; + } + } + return error; +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/Property.cpp b/contrib/llvm/tools/lldb/source/Interpreter/Property.cpp new file mode 100644 index 0000000..e5cf63a --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/Property.cpp @@ -0,0 +1,275 @@ +//===-- Property.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/lldb-python.h" + +#include "lldb/Interpreter/Property.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/UserSettingsController.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/OptionValues.h" + +using namespace lldb; +using namespace lldb_private; + +Property::Property (const PropertyDefinition &definition) : + m_name (definition.name), + m_description (definition.description), + m_value_sp (), + m_is_global (definition.global) +{ + switch (definition.type) + { + case OptionValue::eTypeInvalid: + case OptionValue::eTypeProperties: + break; + case OptionValue::eTypeArch: + // "definition.default_uint_value" is not used + // "definition.default_cstr_value" as a string value that represents the default string value for the architecture/triple + m_value_sp.reset (new OptionValueArch(definition.default_cstr_value)); + break; + + case OptionValue::eTypeArgs: + // "definition.default_uint_value" is always a OptionValue::Type + m_value_sp.reset (new OptionValueArgs()); + break; + + case OptionValue::eTypeArray: + // "definition.default_uint_value" is always a OptionValue::Type + m_value_sp.reset (new OptionValueArray(OptionValue::ConvertTypeToMask((OptionValue::Type)definition.default_uint_value))); + break; + + case OptionValue::eTypeBoolean: + // "definition.default_uint_value" is the default boolean value if + // "definition.default_cstr_value" is NULL, otherwise interpret + // "definition.default_cstr_value" as a string value that represents the default + // value. + if (definition.default_cstr_value) + m_value_sp.reset (new OptionValueBoolean(Args::StringToBoolean (definition.default_cstr_value, false, NULL))); + else + m_value_sp.reset (new OptionValueBoolean(definition.default_uint_value != 0)); + break; + + case OptionValue::eTypeDictionary: + // "definition.default_uint_value" is always a OptionValue::Type + m_value_sp.reset (new OptionValueDictionary(OptionValue::ConvertTypeToMask((OptionValue::Type)definition.default_uint_value))); + break; + + case OptionValue::eTypeEnum: + // "definition.default_uint_value" is the default enumeration value if + // "definition.default_cstr_value" is NULL, otherwise interpret + // "definition.default_cstr_value" as a string value that represents the default + // value. + { + OptionValueEnumeration *enum_value = new OptionValueEnumeration(definition.enum_values, definition.default_uint_value); + m_value_sp.reset (enum_value); + if (definition.default_cstr_value) + { + if (enum_value->SetValueFromCString(definition.default_cstr_value).Success()) + { + enum_value->SetDefaultValue(enum_value->GetCurrentValue()); + // Call Clear() since we don't want the value to appear as + // having been set since we called SetValueFromCString() above. + // Clear will set the current value to the default and clear + // the boolean that says that the value has been set. + enum_value->Clear(); + } + } + } + break; + + case OptionValue::eTypeFileSpec: + // "definition.default_uint_value" represents if the "definition.default_cstr_value" should + // be resolved or not + m_value_sp.reset (new OptionValueFileSpec(FileSpec(definition.default_cstr_value, definition.default_uint_value != 0))); + break; + + case OptionValue::eTypeFileSpecList: + // "definition.default_uint_value" is not used for a OptionValue::eTypeFileSpecList + m_value_sp.reset (new OptionValueFileSpecList()); + break; + + case OptionValue::eTypeFormat: + // "definition.default_uint_value" is the default format enumeration value if + // "definition.default_cstr_value" is NULL, otherwise interpret + // "definition.default_cstr_value" as a string value that represents the default + // value. + { + Format new_format = eFormatInvalid; + if (definition.default_cstr_value) + Args::StringToFormat (definition.default_cstr_value, new_format, NULL); + else + new_format = (Format)definition.default_uint_value; + m_value_sp.reset (new OptionValueFormat(new_format)); + } + break; + + case OptionValue::eTypePathMap: + // "definition.default_uint_value" tells us if notifications should occur for + // path mappings + m_value_sp.reset (new OptionValuePathMappings(definition.default_uint_value != 0)); + break; + + case OptionValue::eTypeRegex: + // "definition.default_uint_value" is used to the regular expression flags + // "definition.default_cstr_value" the default regular expression value + // value. + m_value_sp.reset (new OptionValueRegex(definition.default_cstr_value, definition.default_uint_value)); + break; + + case OptionValue::eTypeSInt64: + // "definition.default_uint_value" is the default integer value if + // "definition.default_cstr_value" is NULL, otherwise interpret + // "definition.default_cstr_value" as a string value that represents the default + // value. + m_value_sp.reset (new OptionValueSInt64(definition.default_cstr_value ? Args::StringToSInt64 (definition.default_cstr_value) : definition.default_uint_value)); + break; + + case OptionValue::eTypeUInt64: + // "definition.default_uint_value" is the default unsigned integer value if + // "definition.default_cstr_value" is NULL, otherwise interpret + // "definition.default_cstr_value" as a string value that represents the default + // value. + m_value_sp.reset (new OptionValueUInt64(definition.default_cstr_value ? Args::StringToUInt64 (definition.default_cstr_value) : definition.default_uint_value)); + break; + + case OptionValue::eTypeUUID: + // "definition.default_uint_value" is not used for a OptionValue::eTypeUUID + // "definition.default_cstr_value" can contain a default UUID value + { + UUID uuid; + if (definition.default_cstr_value) + uuid.SetFromCString (definition.default_cstr_value); + m_value_sp.reset (new OptionValueUUID(uuid)); + } + break; + + case OptionValue::eTypeString: + // "definition.default_uint_value" can contain the string option flags OR'ed together + // "definition.default_cstr_value" can contain a default string value + { + OptionValueString *string_value = new OptionValueString(definition.default_cstr_value); + if (definition.default_uint_value != 0) + string_value->GetOptions().Reset(definition.default_uint_value); + m_value_sp.reset (string_value); + } + break; + } +} + +Property::Property (const ConstString &name, + const ConstString &desc, + bool is_global, + const lldb::OptionValueSP &value_sp) : + m_name (name), + m_description (desc), + m_value_sp (value_sp), + m_is_global (is_global) +{ +} + +bool +Property::DumpQualifiedName(Stream &strm) const +{ + if (m_name) + { + if (m_value_sp->DumpQualifiedName(strm)) + strm.PutChar('.'); + strm << m_name; + return true; + } + return false; +} + + +void +Property::Dump (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) const +{ + if (m_value_sp) + { + const bool dump_desc = dump_mask & OptionValue::eDumpOptionDescription; + const bool transparent = m_value_sp->ValueIsTransparent (); + if (dump_desc || !transparent) + { + if ((dump_mask & OptionValue::eDumpOptionName) && m_name) + { + DumpQualifiedName(strm); + if (dump_mask & ~OptionValue::eDumpOptionName) + strm.PutChar(' '); + } + } + if (dump_desc) + { + const char *desc = GetDescription(); + if (desc) + strm.Printf ("-- %s", desc); + + if (transparent && (dump_mask == (OptionValue::eDumpOptionName | OptionValue::eDumpOptionDescription))) + strm.EOL(); + } + m_value_sp->DumpValue(exe_ctx, strm, dump_mask); + } +} + + +void +Property::DumpDescription (CommandInterpreter &interpreter, + Stream &strm, + uint32_t output_width, + bool display_qualified_name) const +{ + if (m_value_sp) + { + const char *desc = GetDescription(); + + if (desc) + { + StreamString qualified_name; + const OptionValueProperties *sub_properties = m_value_sp->GetAsProperties(); + if (sub_properties) + { + strm.EOL(); + + if (m_value_sp->DumpQualifiedName(qualified_name)) + strm.Printf("'%s' variables:\n\n", qualified_name.GetString().c_str()); + sub_properties->DumpAllDescriptions(interpreter, strm); + } + else + { + if (desc) + { + if (display_qualified_name) + { + StreamString qualified_name; + DumpQualifiedName(qualified_name); + interpreter.OutputFormattedHelpText (strm, + qualified_name.GetString().c_str(), + "--", + desc, + output_width); + } + else + { + interpreter.OutputFormattedHelpText (strm, + m_name.GetCString(), + "--", + desc, + output_width); + } + } + } + } + } +} + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/PythonDataObjects.cpp b/contrib/llvm/tools/lldb/source/Interpreter/PythonDataObjects.cpp new file mode 100644 index 0000000..2a1f348 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/PythonDataObjects.cpp @@ -0,0 +1,430 @@ +//===-- PythonDataObjects.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// In order to guarantee correct working with Python, Python.h *MUST* be +// the *FIRST* header file included here. +#ifdef LLDB_DISABLE_PYTHON + +// Python is disabled in this build + +#else + +#if defined (__APPLE__) +#include <Python/Python.h> +#else +#include <Python.h> +#endif + +#include <stdio.h> + +#include "lldb/Core/Stream.h" +#include "lldb/Host/File.h" +#include "lldb/Interpreter/PythonDataObjects.h" +#include "lldb/Interpreter/ScriptInterpreter.h" + +using namespace lldb_private; +using namespace lldb; + +//---------------------------------------------------------------------- +// PythonObject +//---------------------------------------------------------------------- +PythonObject::PythonObject (const lldb::ScriptInterpreterObjectSP &script_object_sp) : + m_py_obj (NULL) +{ + if (script_object_sp) + Reset ((PyObject *)script_object_sp->GetObject()); +} + +void +PythonObject::Dump (Stream &strm) const +{ + if (m_py_obj) + { + FILE *file = ::tmpfile(); + if (file) + { + ::PyObject_Print (m_py_obj, file, 0); + const long length = ftell (file); + if (length) + { + ::rewind(file); + std::vector<char> file_contents (length,'\0'); + const size_t length_read = ::fread (file_contents.data(), 1, file_contents.size(), file); + if (length_read > 0) + strm.Write (file_contents.data(), length_read); + } + ::fclose (file); + } + } + else + strm.PutCString ("NULL"); +} + +PythonString +PythonObject::Repr () +{ + if (!m_py_obj) + return PythonString (); + PyObject *repr = PyObject_Repr(m_py_obj); + if (!repr) + return PythonString (); + return PythonString(repr); +} + +PythonString +PythonObject::Str () +{ + if (!m_py_obj) + return PythonString (); + PyObject *str = PyObject_Str(m_py_obj); + if (!str) + return PythonString (); + return PythonString(str); +} + +//---------------------------------------------------------------------- +// PythonString +//---------------------------------------------------------------------- + +PythonString::PythonString (PyObject *py_obj) : + PythonObject(py_obj) +{ +} + +PythonString::PythonString (const PythonObject &object) : + PythonObject(object.GetPythonObject()) +{ +} + +PythonString::PythonString (const lldb::ScriptInterpreterObjectSP &script_object_sp) : + PythonObject (script_object_sp) +{ +} + +PythonString::PythonString (const char* string) : + PythonObject(PyString_FromString(string)) +{ +} + +PythonString::PythonString () : + PythonObject() +{ +} + +PythonString::~PythonString () +{ +} + +bool +PythonString::Reset (PyObject *py_obj) +{ + if (py_obj && PyString_Check(py_obj)) + return PythonObject::Reset(py_obj); + + PythonObject::Reset(NULL); + return py_obj == NULL; +} + +const char* +PythonString::GetString() const +{ + if (m_py_obj) + return PyString_AsString(m_py_obj); + return NULL; +} + +size_t +PythonString::GetSize() const +{ + if (m_py_obj) + return PyString_Size(m_py_obj); + return 0; +} + +void +PythonString::SetString (const char* string) +{ + PythonObject::Reset(PyString_FromString(string)); +} + +//---------------------------------------------------------------------- +// PythonInteger +//---------------------------------------------------------------------- + +PythonInteger::PythonInteger (PyObject *py_obj) : + PythonObject(py_obj) +{ +} + +PythonInteger::PythonInteger (const PythonObject &object) : + PythonObject(object.GetPythonObject()) +{ +} + +PythonInteger::PythonInteger (const lldb::ScriptInterpreterObjectSP &script_object_sp) : + PythonObject (script_object_sp) +{ +} + +PythonInteger::PythonInteger (int64_t value) : + PythonObject(PyInt_FromLong(value)) +{ +} + + +PythonInteger::~PythonInteger () +{ +} + +bool +PythonInteger::Reset (PyObject *py_obj) +{ + if (py_obj && PyInt_Check(py_obj)) + return PythonObject::Reset(py_obj); + + PythonObject::Reset(NULL); + return py_obj == NULL; +} + +int64_t +PythonInteger::GetInteger() +{ + if (m_py_obj) + return PyInt_AsLong(m_py_obj); + else + return UINT64_MAX; +} + +void +PythonInteger::SetInteger (int64_t value) +{ + PythonObject::Reset(PyInt_FromLong(value)); +} + +//---------------------------------------------------------------------- +// PythonList +//---------------------------------------------------------------------- + +PythonList::PythonList () : + PythonObject(PyList_New(0)) +{ +} + +PythonList::PythonList (uint32_t count) : + PythonObject(PyList_New(count)) +{ +} + +PythonList::PythonList (PyObject *py_obj) : + PythonObject(py_obj) +{ +} + + +PythonList::PythonList (const PythonObject &object) : + PythonObject(object.GetPythonObject()) +{ +} + +PythonList::PythonList (const lldb::ScriptInterpreterObjectSP &script_object_sp) : + PythonObject (script_object_sp) +{ +} + +PythonList::~PythonList () +{ +} + +bool +PythonList::Reset (PyObject *py_obj) +{ + if (py_obj && PyList_Check(py_obj)) + return PythonObject::Reset(py_obj); + + PythonObject::Reset(NULL); + return py_obj == NULL; +} + +uint32_t +PythonList::GetSize() +{ + if (m_py_obj) + return PyList_GET_SIZE(m_py_obj); + return 0; +} + +PythonObject +PythonList::GetItemAtIndex (uint32_t index) +{ + if (m_py_obj) + return PythonObject(PyList_GetItem(m_py_obj, index)); + return NULL; +} + +void +PythonList::SetItemAtIndex (uint32_t index, const PythonObject & object) +{ + if (m_py_obj && object) + PyList_SetItem(m_py_obj, index, object.GetPythonObject()); +} + +void +PythonList::AppendItem (const PythonObject &object) +{ + if (m_py_obj && object) + PyList_Append(m_py_obj, object.GetPythonObject()); +} + +//---------------------------------------------------------------------- +// PythonDictionary +//---------------------------------------------------------------------- + +PythonDictionary::PythonDictionary () : + PythonObject(PyDict_New()) +{ +} + +PythonDictionary::PythonDictionary (PyObject *py_obj) : + PythonObject(py_obj) +{ +} + + +PythonDictionary::PythonDictionary (const PythonObject &object) : + PythonObject(object.GetPythonObject()) +{ +} + +PythonDictionary::PythonDictionary (const lldb::ScriptInterpreterObjectSP &script_object_sp) : + PythonObject (script_object_sp) +{ +} + +PythonDictionary::~PythonDictionary () +{ +} + +bool +PythonDictionary::Reset (PyObject *py_obj) +{ + if (py_obj && PyDict_Check(py_obj)) + return PythonObject::Reset(py_obj); + + PythonObject::Reset(NULL); + return py_obj == NULL; +} + +uint32_t +PythonDictionary::GetSize() +{ + if (m_py_obj) + return PyDict_Size(m_py_obj); + return 0; +} + +PythonObject +PythonDictionary::GetItemForKey (const char *key) const +{ + if (key && key[0]) + { + PythonString python_key(key); + return GetItemForKey(python_key); + } + return NULL; +} + + +PythonObject +PythonDictionary::GetItemForKey (const PythonString &key) const +{ + if (m_py_obj && key) + return PythonObject(PyDict_GetItem(m_py_obj, key.GetPythonObject())); + return PythonObject(); +} + + +const char * +PythonDictionary::GetItemForKeyAsString (const PythonString &key, const char *fail_value) const +{ + if (m_py_obj && key) + { + PyObject *py_obj = PyDict_GetItem(m_py_obj, key.GetPythonObject()); + if (py_obj && PyString_Check(py_obj)) + return PyString_AsString(py_obj); + } + return fail_value; +} + +int64_t +PythonDictionary::GetItemForKeyAsInteger (const PythonString &key, int64_t fail_value) const +{ + if (m_py_obj && key) + { + PyObject *py_obj = PyDict_GetItem(m_py_obj, key.GetPythonObject()); + if (py_obj) + { + if (PyInt_Check(py_obj)) + return PyInt_AsLong(py_obj); + + if (PyLong_Check(py_obj)) + return PyLong_AsLong(py_obj); + } + } + return fail_value; +} + +PythonList +PythonDictionary::GetKeys () const +{ + if (m_py_obj) + return PythonList(PyDict_Keys(m_py_obj)); + return PythonList(); +} + +PythonString +PythonDictionary::GetKeyAtPosition (uint32_t pos) const +{ + PyObject *key, *value; + Py_ssize_t pos_iter = 0; + + if (m_py_obj) + { + while (PyDict_Next(m_py_obj, &pos_iter, &key, &value)) + { + if (pos-- == 0) + return PythonString(key); + } + } + return PythonString(); +} + +PythonObject +PythonDictionary::GetValueAtPosition (uint32_t pos) const +{ + PyObject *key, *value; + Py_ssize_t pos_iter = 0; + + if (!m_py_obj) + return NULL; + + while (PyDict_Next(m_py_obj, &pos_iter, &key, &value)) { + if (pos-- == 0) + return PythonObject(value); + } + return PythonObject(); +} + +void +PythonDictionary::SetItemForKey (const PythonString &key, const PythonObject &value) +{ + if (m_py_obj && key && value) + PyDict_SetItem(m_py_obj, key.GetPythonObject(), value.GetPythonObject()); +} + +#endif diff --git a/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreter.cpp b/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreter.cpp new file mode 100644 index 0000000..6731473 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreter.cpp @@ -0,0 +1,105 @@ +//===-- ScriptInterpreter.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/lldb-python.h" + +#include "lldb/Interpreter/ScriptInterpreter.h" + +#include <string> +#include <stdlib.h> +#include <stdio.h> + +#include "lldb/Core/Error.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StringList.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/ScriptInterpreterPython.h" +#include "lldb/Utility/PseudoTerminal.h" + +using namespace lldb; +using namespace lldb_private; + +ScriptInterpreter::ScriptInterpreter (CommandInterpreter &interpreter, lldb::ScriptLanguage script_lang) : + m_interpreter (interpreter), + m_script_lang (script_lang) +{ +} + +ScriptInterpreter::~ScriptInterpreter () +{ +} + +CommandInterpreter & +ScriptInterpreter::GetCommandInterpreter () +{ + return m_interpreter; +} + +void +ScriptInterpreter::CollectDataForBreakpointCommandCallback +( + BreakpointOptions *bp_options, + CommandReturnObject &result +) +{ + result.SetStatus (eReturnStatusFailed); + result.AppendError ("ScriptInterpreter::GetScriptCommands(StringList &) is not implemented."); +} + +void +ScriptInterpreter::CollectDataForWatchpointCommandCallback +( + WatchpointOptions *bp_options, + CommandReturnObject &result +) +{ + result.SetStatus (eReturnStatusFailed); + result.AppendError ("ScriptInterpreter::GetScriptCommands(StringList &) is not implemented."); +} + +std::string +ScriptInterpreter::LanguageToString (lldb::ScriptLanguage language) +{ + std::string return_value; + + switch (language) + { + case eScriptLanguageNone: + return_value = "None"; + break; + case eScriptLanguagePython: + return_value = "Python"; + break; + } + + return return_value; +} + +std::unique_ptr<ScriptInterpreterLocker> +ScriptInterpreter::AcquireInterpreterLock () +{ + return std::unique_ptr<ScriptInterpreterLocker>(new ScriptInterpreterLocker()); +} + +void +ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_callback) +{ +#ifndef LLDB_DISABLE_PYTHON + ScriptInterpreterPython::InitializeInterpreter (python_swig_init_callback); +#endif // #ifndef LLDB_DISABLE_PYTHON +} + +void +ScriptInterpreter::TerminateInterpreter () +{ +#ifndef LLDB_DISABLE_PYTHON + ScriptInterpreterPython::TerminateInterpreter (); +#endif // #ifndef LLDB_DISABLE_PYTHON +} + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterNone.cpp b/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterNone.cpp new file mode 100644 index 0000000..6a44114 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterNone.cpp @@ -0,0 +1,43 @@ +//===-- ScriptInterpreterNone.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/lldb-python.h" + +#include "lldb/Interpreter/ScriptInterpreterNone.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StringList.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Interpreter/CommandInterpreter.h" + +using namespace lldb; +using namespace lldb_private; + +ScriptInterpreterNone::ScriptInterpreterNone (CommandInterpreter &interpreter) : + ScriptInterpreter (interpreter, eScriptLanguageNone) +{ +} + +ScriptInterpreterNone::~ScriptInterpreterNone () +{ +} + +bool +ScriptInterpreterNone::ExecuteOneLine (const char *command, CommandReturnObject *, const ExecuteScriptOptions&) +{ + m_interpreter.GetDebugger().GetErrorStream().PutCString ("error: there is no embedded script interpreter in this mode.\n"); + return false; +} + +void +ScriptInterpreterNone::ExecuteInterpreterLoop () +{ + m_interpreter.GetDebugger().GetErrorStream().PutCString ("error: there is no embedded script interpreter in this mode.\n"); +} + + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterPython.cpp new file mode 100644 index 0000000..9d9b8d9 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterPython.cpp @@ -0,0 +1,3166 @@ +//===-- ScriptInterpreterPython.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// In order to guarantee correct working with Python, Python.h *MUST* be +// the *FIRST* header file included here. +#ifdef LLDB_DISABLE_PYTHON + +// Python is disabled in this build + +#else + +#if defined (__APPLE__) +#include <Python/Python.h> +#else +#include <Python.h> +#endif + +#include "lldb/Interpreter/ScriptInterpreterPython.h" + +#include <stdlib.h> +#include <stdio.h> + +#include <string> + +#include "lldb/API/SBValue.h" +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Breakpoint/WatchpointOptions.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Timer.h" +#include "lldb/Host/Host.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; + + +static ScriptInterpreter::SWIGInitCallback g_swig_init_callback = NULL; +static ScriptInterpreter::SWIGBreakpointCallbackFunction g_swig_breakpoint_callback = NULL; +static ScriptInterpreter::SWIGWatchpointCallbackFunction g_swig_watchpoint_callback = NULL; +static ScriptInterpreter::SWIGPythonTypeScriptCallbackFunction g_swig_typescript_callback = NULL; +static ScriptInterpreter::SWIGPythonCreateSyntheticProvider g_swig_synthetic_script = NULL; +static ScriptInterpreter::SWIGPythonCalculateNumChildren g_swig_calc_children = NULL; +static ScriptInterpreter::SWIGPythonGetChildAtIndex g_swig_get_child_index = NULL; +static ScriptInterpreter::SWIGPythonGetIndexOfChildWithName g_swig_get_index_child = NULL; +static ScriptInterpreter::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue = NULL; +static ScriptInterpreter::SWIGPythonUpdateSynthProviderInstance g_swig_update_provider = NULL; +static ScriptInterpreter::SWIGPythonMightHaveChildrenSynthProviderInstance g_swig_mighthavechildren_provider = NULL; +static ScriptInterpreter::SWIGPythonCallCommand g_swig_call_command = NULL; +static ScriptInterpreter::SWIGPythonCallModuleInit g_swig_call_module_init = NULL; +static ScriptInterpreter::SWIGPythonCreateOSPlugin g_swig_create_os_plugin = NULL; +static ScriptInterpreter::SWIGPythonScriptKeyword_Process g_swig_run_script_keyword_process = NULL; +static ScriptInterpreter::SWIGPythonScriptKeyword_Thread g_swig_run_script_keyword_thread = NULL; +static ScriptInterpreter::SWIGPythonScriptKeyword_Target g_swig_run_script_keyword_target = NULL; +static ScriptInterpreter::SWIGPythonScriptKeyword_Frame g_swig_run_script_keyword_frame = NULL; + +// these are the Pythonic implementations of the required callbacks +// these are scripting-language specific, which is why they belong here +// we still need to use function pointers to them instead of relying +// on linkage-time resolution because the SWIG stuff and this file +// get built at different times +extern "C" bool +LLDBSwigPythonBreakpointCallbackFunction (const char *python_function_name, + const char *session_dictionary_name, + const lldb::StackFrameSP& sb_frame, + const lldb::BreakpointLocationSP& sb_bp_loc); + +extern "C" bool +LLDBSwigPythonWatchpointCallbackFunction (const char *python_function_name, + const char *session_dictionary_name, + const lldb::StackFrameSP& sb_frame, + const lldb::WatchpointSP& sb_wp); + +extern "C" bool +LLDBSwigPythonCallTypeScript (const char *python_function_name, + void *session_dictionary, + const lldb::ValueObjectSP& valobj_sp, + void** pyfunct_wrapper, + std::string& retval); + +extern "C" void* +LLDBSwigPythonCreateSyntheticProvider (const char *python_class_name, + const char *session_dictionary_name, + const lldb::ValueObjectSP& valobj_sp); + + +extern "C" uint32_t +LLDBSwigPython_CalculateNumChildren (void *implementor); + +extern "C" void * +LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx); + +extern "C" int +LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_name); + +extern "C" void * +LLDBSWIGPython_CastPyObjectToSBValue (void* data); + +extern "C" bool +LLDBSwigPython_UpdateSynthProviderInstance (void* implementor); + +extern "C" bool +LLDBSwigPython_MightHaveChildrenSynthProviderInstance (void* implementor); + +extern "C" bool +LLDBSwigPythonCallCommand (const char *python_function_name, + const char *session_dictionary_name, + lldb::DebuggerSP& debugger, + const char* args, + lldb_private::CommandReturnObject &cmd_retobj); + +extern "C" bool +LLDBSwigPythonCallModuleInit (const char *python_module_name, + const char *session_dictionary_name, + lldb::DebuggerSP& debugger); + +extern "C" void* +LLDBSWIGPythonCreateOSPlugin (const char *python_class_name, + const char *session_dictionary_name, + const lldb::ProcessSP& process_sp); + +extern "C" bool +LLDBSWIGPythonRunScriptKeywordProcess (const char* python_function_name, + const char* session_dictionary_name, + lldb::ProcessSP& process, + std::string& output); + +extern "C" bool +LLDBSWIGPythonRunScriptKeywordThread (const char* python_function_name, + const char* session_dictionary_name, + lldb::ThreadSP& thread, + std::string& output); + +extern "C" bool +LLDBSWIGPythonRunScriptKeywordTarget (const char* python_function_name, + const char* session_dictionary_name, + lldb::TargetSP& target, + std::string& output); + +extern "C" bool +LLDBSWIGPythonRunScriptKeywordFrame (const char* python_function_name, + const char* session_dictionary_name, + lldb::StackFrameSP& frame, + std::string& output); + +static int +_check_and_flush (FILE *stream) +{ + int prev_fail = ferror (stream); + return fflush (stream) || prev_fail ? EOF : 0; +} + +ScriptInterpreterPython::Locker::Locker (ScriptInterpreterPython *py_interpreter, + uint16_t on_entry, + uint16_t on_leave, + FILE* wait_msg_handle) : + ScriptInterpreterLocker (), + m_teardown_session( (on_leave & TearDownSession) == TearDownSession ), + m_python_interpreter(py_interpreter), + m_tmp_fh(wait_msg_handle) +{ + if (m_python_interpreter && !m_tmp_fh) + m_tmp_fh = (m_python_interpreter->m_dbg_stdout ? m_python_interpreter->m_dbg_stdout : stdout); + + DoAcquireLock(); + if ((on_entry & InitSession) == InitSession) + { + if (DoInitSession((on_entry & InitGlobals) == InitGlobals) == false) + { + // Don't teardown the session if we didn't init it. + m_teardown_session = false; + } + } +} + +bool +ScriptInterpreterPython::Locker::DoAcquireLock() +{ + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE)); + m_GILState = PyGILState_Ensure(); + if (log) + log->Printf("Ensured PyGILState. Previous state = %slocked\n", m_GILState == PyGILState_UNLOCKED ? "un" : ""); + return true; +} + +bool +ScriptInterpreterPython::Locker::DoInitSession(bool init_lldb_globals) +{ + if (!m_python_interpreter) + return false; + return m_python_interpreter->EnterSession (init_lldb_globals); +} + +bool +ScriptInterpreterPython::Locker::DoFreeLock() +{ + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE)); + if (log) + log->Printf("Releasing PyGILState. Returning to state = %slocked\n", m_GILState == PyGILState_UNLOCKED ? "un" : ""); + PyGILState_Release(m_GILState); + return true; +} + +bool +ScriptInterpreterPython::Locker::DoTearDownSession() +{ + if (!m_python_interpreter) + return false; + m_python_interpreter->LeaveSession (); + return true; +} + +ScriptInterpreterPython::Locker::~Locker() +{ + if (m_teardown_session) + DoTearDownSession(); + DoFreeLock(); +} + +ScriptInterpreterPython::PythonInputReaderManager::PythonInputReaderManager (ScriptInterpreterPython *interpreter) : +m_interpreter(interpreter), +m_debugger_sp(), +m_reader_sp(), +m_error(false) +{ + if (m_interpreter == NULL) + { + m_error = true; + return; + } + + m_debugger_sp = m_interpreter->GetCommandInterpreter().GetDebugger().shared_from_this(); + + if (!m_debugger_sp) + { + m_error = true; + return; + } + + m_reader_sp = InputReaderSP(new InputReader(*m_debugger_sp.get())); + + if (!m_reader_sp) + { + m_error = true; + return; + } + + Error error (m_reader_sp->Initialize (ScriptInterpreterPython::PythonInputReaderManager::InputReaderCallback, + m_interpreter, // baton + eInputReaderGranularityLine, // token size, to pass to callback function + NULL, // end token + NULL, // prompt + true)); // echo input + if (error.Fail()) + m_error = true; + else + { + m_debugger_sp->PushInputReader (m_reader_sp); + m_interpreter->m_embedded_thread_input_reader_sp = m_reader_sp; + } +} + +ScriptInterpreterPython::PythonInputReaderManager::~PythonInputReaderManager() +{ + // Nothing to do if either m_interpreter or m_reader_sp is invalid. + if (!m_interpreter || !m_reader_sp) + return; + + m_reader_sp->SetIsDone (true); + if (m_debugger_sp) + m_debugger_sp->PopInputReader(m_reader_sp); + + // Only mess with m_interpreter's counterpart if, indeed, they are the same object. + if (m_reader_sp.get() == m_interpreter->m_embedded_thread_input_reader_sp.get()) + { + m_interpreter->m_embedded_thread_pty.CloseSlaveFileDescriptor(); + m_interpreter->m_embedded_thread_input_reader_sp.reset(); + } +} + +size_t +ScriptInterpreterPython::PythonInputReaderManager::InputReaderCallback (void *baton, + InputReader &reader, + InputReaderAction notification, + const char *bytes, + size_t bytes_len) +{ + lldb::thread_t embedded_interpreter_thread; + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); + + if (baton == NULL) + return 0; + + ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton; + + if (script_interpreter->m_script_lang != eScriptLanguagePython) + return 0; + + switch (notification) + { + case eInputReaderActivate: + { + // Save terminal settings if we can + int input_fd = reader.GetDebugger().GetInputFile().GetDescriptor(); + if (input_fd == File::kInvalidDescriptor) + input_fd = STDIN_FILENO; + + script_interpreter->SaveTerminalState(input_fd); + + char error_str[1024]; + if (script_interpreter->m_embedded_thread_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, error_str, + sizeof(error_str))) + { + if (log) + log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, succeeded in opening master pty (fd = %d).", + script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor()); + { + StreamString run_string; + char error_str[1024]; + const char *pty_slave_name = script_interpreter->m_embedded_thread_pty.GetSlaveName (error_str, sizeof (error_str)); + if (pty_slave_name != NULL && PyThreadState_GetDict() != NULL) + { + ScriptInterpreterPython::Locker locker(script_interpreter, + ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | ScriptInterpreterPython::Locker::InitGlobals, + ScriptInterpreterPython::Locker::FreeAcquiredLock); + run_string.Printf ("run_one_line (%s, 'save_stderr = sys.stderr')", script_interpreter->m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear (); + + run_string.Printf ("run_one_line (%s, 'sys.stderr = sys.stdout')", script_interpreter->m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear (); + + run_string.Printf ("run_one_line (%s, 'save_stdin = sys.stdin')", script_interpreter->m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear (); + + run_string.Printf ("run_one_line (%s, \"sys.stdin = open ('%s', 'r')\")", script_interpreter->m_dictionary_name.c_str(), + pty_slave_name); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear (); + } + } + embedded_interpreter_thread = Host::ThreadCreate ("<lldb.script-interpreter.noninteractive-python>", + ScriptInterpreterPython::PythonInputReaderManager::RunPythonInputReader, + script_interpreter, NULL); + if (IS_VALID_LLDB_HOST_THREAD(embedded_interpreter_thread)) + { + if (log) + log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, succeeded in creating thread (thread_t = %p)", (void *)embedded_interpreter_thread); + Error detach_error; + Host::ThreadDetach (embedded_interpreter_thread, &detach_error); + } + else + { + if (log) + log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, failed in creating thread"); + reader.SetIsDone (true); + } + } + else + { + if (log) + log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, failed to open master pty "); + reader.SetIsDone (true); + } + } + break; + + case eInputReaderDeactivate: + // When another input reader is pushed, don't leave the session... + //script_interpreter->LeaveSession (); + break; + + case eInputReaderReactivate: +// { +// ScriptInterpreterPython::Locker locker(script_interpreter, +// ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession, +// ScriptInterpreterPython::Locker::FreeAcquiredLock); +// } + break; + + case eInputReaderAsynchronousOutputWritten: + break; + + case eInputReaderInterrupt: + { + PyThreadState* state = _PyThreadState_Current; + if (!state) + state = script_interpreter->m_command_thread_state; + if (state) + { + long tid = state->thread_id; + _PyThreadState_Current = state; + int num_threads = PyThreadState_SetAsyncExc(tid, PyExc_KeyboardInterrupt); + if (log) + log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, tid = %ld, num_threads = %d, state = %p", + tid,num_threads,state); + } + else if (log) + log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, state = NULL"); + } + break; + + case eInputReaderEndOfFile: + reader.SetIsDone(true); + break; + + case eInputReaderGotToken: + if (script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor() != -1) + { + if (log) + log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, GotToken, bytes='%s', byte_len = %lu", bytes, + bytes_len); + if (bytes && bytes_len) + ::write (script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor(), bytes, bytes_len); + ::write (script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor(), "\n", 1); + } + else + { + if (log) + log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, GotToken, bytes='%s', byte_len = %lu, Master File Descriptor is bad.", + bytes, + bytes_len); + reader.SetIsDone (true); + } + break; + + case eInputReaderDone: + { + StreamString run_string; + char error_str[1024]; + const char *pty_slave_name = script_interpreter->m_embedded_thread_pty.GetSlaveName (error_str, sizeof (error_str)); + if (pty_slave_name != NULL && PyThreadState_GetDict() != NULL) + { + ScriptInterpreterPython::Locker locker(script_interpreter, + ScriptInterpreterPython::Locker::AcquireLock, + ScriptInterpreterPython::Locker::FreeAcquiredLock); + run_string.Printf ("run_one_line (%s, 'sys.stdin = save_stdin; sys.stderr = save_stderr')", script_interpreter->m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear(); + } + // Restore terminal settings if they were validly saved + if (log) + log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Done, closing down input reader."); + + script_interpreter->RestoreTerminalState (); + + script_interpreter->m_embedded_thread_pty.CloseMasterFileDescriptor(); + } + break; + } + + return bytes_len; +} + +ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interpreter) : + ScriptInterpreter (interpreter, eScriptLanguagePython), + m_embedded_thread_pty (), + m_embedded_python_pty (), + m_embedded_thread_input_reader_sp (), + m_embedded_python_input_reader_sp (), + m_dbg_stdout (interpreter.GetDebugger().GetOutputFile().GetStream()), + m_new_sysout (NULL), + m_old_sysout (NULL), + m_old_syserr (NULL), + m_run_one_line (NULL), + m_dictionary_name (interpreter.GetDebugger().GetInstanceName().AsCString()), + m_terminal_state (), + m_session_is_active (false), + m_valid_session (true), + m_command_thread_state (NULL) +{ + + static int g_initialized = false; + + if (!g_initialized) + { + g_initialized = true; + ScriptInterpreterPython::InitializePrivate (); + } + + m_dictionary_name.append("_dict"); + StreamString run_string; + run_string.Printf ("%s = dict()", m_dictionary_name.c_str()); + + Locker locker(this, + ScriptInterpreterPython::Locker::AcquireLock, + ScriptInterpreterPython::Locker::FreeAcquiredLock); + PyRun_SimpleString (run_string.GetData()); + + run_string.Clear(); + + // Importing 'lldb' module calls SBDebugger::Initialize, which calls Debugger::Initialize, which increments a + // global debugger ref-count; therefore we need to check the ref-count before and after importing lldb, and if the + // ref-count increased we need to call Debugger::Terminate here to decrement the ref-count so that when the final + // call to Debugger::Terminate is made, the ref-count has the correct value. + // + // Bonus question: Why doesn't the ref-count always increase? Because sometimes lldb has already been imported, in + // which case the code inside it, including the call to SBDebugger::Initialize(), does not get executed. + + int old_count = Debugger::TestDebuggerRefCount(); + + run_string.Printf ("run_one_line (%s, 'import copy, os, re, sys, uuid, lldb')", m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + + // WARNING: temporary code that loads Cocoa formatters - this should be done on a per-platform basis rather than loading the whole set + // and letting the individual formatter classes exploit APIs to check whether they can/cannot do their task + run_string.Clear(); + run_string.Printf ("run_one_line (%s, 'import lldb.formatters, lldb.formatters.cpp, pydoc')", m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + + int new_count = Debugger::TestDebuggerRefCount(); + + if (new_count > old_count) + Debugger::Terminate(); + + run_string.Clear(); + run_string.Printf ("run_one_line (%s, 'lldb.debugger_unique_id = %" PRIu64 "; pydoc.pager = pydoc.plainpager')", m_dictionary_name.c_str(), + interpreter.GetDebugger().GetID()); + PyRun_SimpleString (run_string.GetData()); + + if (m_dbg_stdout != NULL) + { + m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush); + } + + // get the output file handle from the debugger (if any) + File& out_file = interpreter.GetDebugger().GetOutputFile(); + if (out_file.IsValid()) + ResetOutputFileHandle(out_file.GetStream()); +} + +ScriptInterpreterPython::~ScriptInterpreterPython () +{ + Debugger &debugger = GetCommandInterpreter().GetDebugger(); + + if (m_embedded_thread_input_reader_sp.get() != NULL) + { + m_embedded_thread_input_reader_sp->SetIsDone (true); + m_embedded_thread_pty.CloseSlaveFileDescriptor(); + const InputReaderSP reader_sp = m_embedded_thread_input_reader_sp; + debugger.PopInputReader (reader_sp); + m_embedded_thread_input_reader_sp.reset(); + } + + if (m_embedded_python_input_reader_sp.get() != NULL) + { + m_embedded_python_input_reader_sp->SetIsDone (true); + m_embedded_python_pty.CloseSlaveFileDescriptor(); + const InputReaderSP reader_sp = m_embedded_python_input_reader_sp; + debugger.PopInputReader (reader_sp); + m_embedded_python_input_reader_sp.reset(); + } + + if (m_new_sysout) + { + Locker locker(this, + ScriptInterpreterPython::Locker::AcquireLock, + ScriptInterpreterPython::Locker::FreeLock); + Py_XDECREF ((PyObject*)m_new_sysout); + } +} + +void +ScriptInterpreterPython::ResetOutputFileHandle (FILE *fh) +{ + if (fh == NULL) + return; + + m_dbg_stdout = fh; + + Locker locker(this, + ScriptInterpreterPython::Locker::AcquireLock, + ScriptInterpreterPython::Locker::FreeAcquiredLock); + + m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush); +} + +void +ScriptInterpreterPython::SaveTerminalState (int fd) +{ + // Python mucks with the terminal state of STDIN. If we can possibly avoid + // this by setting the file handles up correctly prior to entering the + // interpreter we should. For now we save and restore the terminal state + // on the input file handle. + m_terminal_state.Save (fd, false); +} + +void +ScriptInterpreterPython::RestoreTerminalState () +{ + // Python mucks with the terminal state of STDIN. If we can possibly avoid + // this by setting the file handles up correctly prior to entering the + // interpreter we should. For now we save and restore the terminal state + // on the input file handle. + m_terminal_state.Restore(); +} + +void +ScriptInterpreterPython::LeaveSession () +{ + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); + if (log) + log->PutCString("ScriptInterpreterPython::LeaveSession()"); + + // checking that we have a valid thread state - since we use our own threading and locking + // in some (rare) cases during cleanup Python may end up believing we have no thread state + // and PyImport_AddModule will crash if that is the case - since that seems to only happen + // when destroying the SBDebugger, we can make do without clearing up stdout and stderr + + // rdar://problem/11292882 + // When the current thread state is NULL, PyThreadState_Get() issues a fatal error. + if (PyThreadState_GetDict()) + { + PyObject *sysmod = PyImport_AddModule ("sys"); + PyObject *sysdict = PyModule_GetDict (sysmod); + + if (m_new_sysout && sysmod && sysdict) + { + if (m_old_sysout) + PyDict_SetItemString (sysdict, "stdout", (PyObject*)m_old_sysout); + if (m_old_syserr) + PyDict_SetItemString (sysdict, "stderr", (PyObject*)m_old_syserr); + } + } + + m_session_is_active = false; +} + +bool +ScriptInterpreterPython::EnterSession (bool init_lldb_globals) +{ + // If we have already entered the session, without having officially 'left' it, then there is no need to + // 'enter' it again. + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); + if (m_session_is_active) + { + if (log) + log->Printf("ScriptInterpreterPython::EnterSession(init_lldb_globals=%i) session is already active, returning without doing anything", init_lldb_globals); + return false; + } + + if (log) + log->Printf("ScriptInterpreterPython::EnterSession(init_lldb_globals=%i)", init_lldb_globals); + + + m_session_is_active = true; + + StreamString run_string; + + if (init_lldb_globals) + { + run_string.Printf ( "run_one_line (%s, 'lldb.debugger_unique_id = %" PRIu64, m_dictionary_name.c_str(), GetCommandInterpreter().GetDebugger().GetID()); + run_string.Printf ( "; lldb.debugger = lldb.SBDebugger.FindDebuggerWithID (%" PRIu64 ")", GetCommandInterpreter().GetDebugger().GetID()); + run_string.PutCString ("; lldb.target = lldb.debugger.GetSelectedTarget()"); + run_string.PutCString ("; lldb.process = lldb.target.GetProcess()"); + run_string.PutCString ("; lldb.thread = lldb.process.GetSelectedThread ()"); + run_string.PutCString ("; lldb.frame = lldb.thread.GetSelectedFrame ()"); + run_string.PutCString ("')"); + } + else + { + // If we aren't initing the globals, we should still always set the debugger (since that is always unique.) + run_string.Printf ( "run_one_line (%s, \"lldb.debugger_unique_id = %" PRIu64, m_dictionary_name.c_str(), GetCommandInterpreter().GetDebugger().GetID()); + run_string.Printf ( "; lldb.debugger = lldb.SBDebugger.FindDebuggerWithID (%" PRIu64 ")", GetCommandInterpreter().GetDebugger().GetID()); + run_string.PutCString ("\")"); + } + + PyRun_SimpleString (run_string.GetData()); + run_string.Clear(); + + PyObject *sysmod = PyImport_AddModule ("sys"); + PyObject *sysdict = PyModule_GetDict (sysmod); + + if (m_new_sysout && sysmod && sysdict) + { + m_old_sysout = PyDict_GetItemString(sysdict, "stdout"); + m_old_syserr = PyDict_GetItemString(sysdict, "stderr"); + if (m_new_sysout) + { + PyDict_SetItemString (sysdict, "stdout", (PyObject*)m_new_sysout); + PyDict_SetItemString (sysdict, "stderr", (PyObject*)m_new_sysout); + } + } + + if (PyErr_Occurred()) + PyErr_Clear (); + + return true; +} + +static PyObject* +FindSessionDictionary (const char* dict_name) +{ + static std::map<ConstString,PyObject*> g_dict_map; + + ConstString dict(dict_name); + + std::map<ConstString,PyObject*>::iterator iter = g_dict_map.find(dict); + + if (iter != g_dict_map.end()) + return iter->second; + + PyObject *main_mod = PyImport_AddModule ("__main__"); + if (main_mod != NULL) + { + PyObject *main_dict = PyModule_GetDict (main_mod); + if ((main_dict != NULL) + && PyDict_Check (main_dict)) + { + // Go through the main dictionary looking for the correct python script interpreter dictionary + PyObject *key, *value; + Py_ssize_t pos = 0; + + while (PyDict_Next (main_dict, &pos, &key, &value)) + { + // We have stolen references to the key and value objects in the dictionary; we need to increment + // them now so that Python's garbage collector doesn't collect them out from under us. + Py_INCREF (key); + Py_INCREF (value); + if (strcmp (PyString_AsString (key), dict_name) == 0) + { + g_dict_map[dict] = value; + return value; + } + } + } + } + return NULL; +} + +static std::string +GenerateUniqueName (const char* base_name_wanted, + uint32_t& functions_counter, + void* name_token = NULL) +{ + StreamString sstr; + + if (!base_name_wanted) + return std::string(); + + if (!name_token) + sstr.Printf ("%s_%d", base_name_wanted, functions_counter++); + else + sstr.Printf ("%s_%p", base_name_wanted, name_token); + + return sstr.GetString(); +} + +bool +ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObject *result, const ExecuteScriptOptions &options) +{ + if (!m_valid_session) + return false; + + // We want to call run_one_line, passing in the dictionary and the command string. We cannot do this through + // PyRun_SimpleString here because the command string may contain escaped characters, and putting it inside + // another string to pass to PyRun_SimpleString messes up the escaping. So we use the following more complicated + // method to pass the command string directly down to Python. + + Locker locker(this, + ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0), + ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); + + bool success = false; + + if (command) + { + // Find the correct script interpreter dictionary in the main module. + PyObject *script_interpreter_dict = FindSessionDictionary(m_dictionary_name.c_str()); + if (script_interpreter_dict != NULL) + { + PyObject *pfunc = (PyObject*)m_run_one_line; + PyObject *pmod = PyImport_AddModule ("lldb.embedded_interpreter"); + if (pmod != NULL) + { + PyObject *pmod_dict = PyModule_GetDict (pmod); + if ((pmod_dict != NULL) + && PyDict_Check (pmod_dict)) + { + if (!pfunc) + { + PyObject *key, *value; + Py_ssize_t pos = 0; + + while (PyDict_Next (pmod_dict, &pos, &key, &value)) + { + Py_INCREF (key); + Py_INCREF (value); + if (strcmp (PyString_AsString (key), "run_one_line") == 0) + { + pfunc = value; + break; + } + } + m_run_one_line = pfunc; + } + + if (pfunc && PyCallable_Check (pfunc)) + { + PyObject *pargs = Py_BuildValue("(Os)",script_interpreter_dict,command); + if (pargs != NULL) + { + PyObject *pvalue = NULL; + { // scope for PythonInputReaderManager + PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); + pvalue = PyObject_CallObject (pfunc, pargs); + } + Py_XDECREF (pargs); + if (pvalue != NULL) + { + Py_XDECREF (pvalue); + success = true; + } + else if (options.GetMaskoutErrors() && PyErr_Occurred ()) + { + PyErr_Print(); + PyErr_Clear(); + } + } + } + } + } + Py_INCREF (script_interpreter_dict); + } + + if (success) + return true; + + // The one-liner failed. Append the error message. + if (result) + result->AppendErrorWithFormat ("python failed attempting to evaluate '%s'\n", command); + return false; + } + + if (result) + result->AppendError ("empty command passed to python\n"); + return false; +} + +size_t +ScriptInterpreterPython::InputReaderCallback +( + void *baton, + InputReader &reader, + InputReaderAction notification, + const char *bytes, + size_t bytes_len +) +{ + lldb::thread_t embedded_interpreter_thread; + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); + + if (baton == NULL) + return 0; + + ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton; + + if (script_interpreter->m_script_lang != eScriptLanguagePython) + return 0; + + switch (notification) + { + case eInputReaderActivate: + { + StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); + bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); + if (!batch_mode) + { + out_stream->Printf ("Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.\n"); + out_stream->Flush(); + } + + // Save terminal settings if we can + int input_fd = reader.GetDebugger().GetInputFile().GetDescriptor(); + if (input_fd == File::kInvalidDescriptor) + input_fd = STDIN_FILENO; + + script_interpreter->SaveTerminalState(input_fd); + + { + ScriptInterpreterPython::Locker locker(script_interpreter, + ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | ScriptInterpreterPython::Locker::InitGlobals, + ScriptInterpreterPython::Locker::FreeAcquiredLock); + } + + char error_str[1024]; + if (script_interpreter->m_embedded_python_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, error_str, + sizeof(error_str))) + { + if (log) + log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, succeeded in opening master pty (fd = %d).", + script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor()); + embedded_interpreter_thread = Host::ThreadCreate ("<lldb.script-interpreter.embedded-python-loop>", + ScriptInterpreterPython::RunEmbeddedPythonInterpreter, + script_interpreter, NULL); + if (IS_VALID_LLDB_HOST_THREAD(embedded_interpreter_thread)) + { + if (log) + log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, succeeded in creating thread (thread_t = %p)", (void *)embedded_interpreter_thread); + Error detach_error; + Host::ThreadDetach (embedded_interpreter_thread, &detach_error); + } + else + { + if (log) + log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, failed in creating thread"); + reader.SetIsDone (true); + } + } + else + { + if (log) + log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, failed to open master pty "); + reader.SetIsDone (true); + } + } + break; + + case eInputReaderDeactivate: + // When another input reader is pushed, don't leave the session... + //script_interpreter->LeaveSession (); + break; + + case eInputReaderReactivate: + { + ScriptInterpreterPython::Locker locker (script_interpreter, + ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession, + ScriptInterpreterPython::Locker::FreeAcquiredLock); + } + break; + + case eInputReaderAsynchronousOutputWritten: + break; + + case eInputReaderInterrupt: + ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "raise KeyboardInterrupt\n", 24); + break; + + case eInputReaderEndOfFile: + ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "quit()\n", 7); + break; + + case eInputReaderGotToken: + if (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor() != -1) + { + if (log) + log->Printf ("ScriptInterpreterPython::InputReaderCallback, GotToken, bytes='%s', byte_len = %lu", bytes, + bytes_len); + if (bytes && bytes_len) + { + if ((int) bytes[0] == 4) + ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "quit()", 6); + else + ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), bytes, bytes_len); + } + ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "\n", 1); + } + else + { + if (log) + log->Printf ("ScriptInterpreterPython::InputReaderCallback, GotToken, bytes='%s', byte_len = %lu, Master File Descriptor is bad.", + bytes, + bytes_len); + reader.SetIsDone (true); + } + + break; + + case eInputReaderDone: + { + Locker locker(script_interpreter, + ScriptInterpreterPython::Locker::AcquireLock, + ScriptInterpreterPython::Locker::FreeAcquiredLock); + script_interpreter->LeaveSession (); + } + + // Restore terminal settings if they were validly saved + if (log) + log->Printf ("ScriptInterpreterPython::InputReaderCallback, Done, closing down input reader."); + + script_interpreter->RestoreTerminalState (); + + script_interpreter->m_embedded_python_pty.CloseMasterFileDescriptor(); + break; + } + + return bytes_len; +} + + +void +ScriptInterpreterPython::ExecuteInterpreterLoop () +{ + Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); + + Debugger &debugger = GetCommandInterpreter().GetDebugger(); + + // At the moment, the only time the debugger does not have an input file handle is when this is called + // directly from Python, in which case it is both dangerous and unnecessary (not to mention confusing) to + // try to embed a running interpreter loop inside the already running Python interpreter loop, so we won't + // do it. + + if (!debugger.GetInputFile().IsValid()) + return; + + InputReaderSP reader_sp (new InputReader(debugger)); + if (reader_sp) + { + Error error (reader_sp->Initialize (ScriptInterpreterPython::InputReaderCallback, + this, // baton + eInputReaderGranularityLine, // token size, to pass to callback function + NULL, // end token + NULL, // prompt + true)); // echo input + + if (error.Success()) + { + debugger.PushInputReader (reader_sp); + m_embedded_python_input_reader_sp = reader_sp; + } + } +} + +bool +ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string, + ScriptInterpreter::ScriptReturnType return_type, + void *ret_value, + const ExecuteScriptOptions &options) +{ + + Locker locker(this, + ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0), + ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); + + PyObject *py_return = NULL; + PyObject *mainmod = PyImport_AddModule ("__main__"); + PyObject *globals = PyModule_GetDict (mainmod); + PyObject *locals = NULL; + PyObject *py_error = NULL; + bool ret_success = false; + bool should_decrement_locals = false; + int success; + + locals = FindSessionDictionary(m_dictionary_name.c_str()); + + if (locals == NULL) + { + locals = PyObject_GetAttrString (globals, m_dictionary_name.c_str()); + should_decrement_locals = true; + } + + if (locals == NULL) + { + locals = globals; + should_decrement_locals = false; + } + + py_error = PyErr_Occurred(); + if (py_error != NULL) + PyErr_Clear(); + + if (in_string != NULL) + { + { // scope for PythonInputReaderManager + PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); + py_return = PyRun_String (in_string, Py_eval_input, globals, locals); + if (py_return == NULL) + { + py_error = PyErr_Occurred (); + if (py_error != NULL) + PyErr_Clear (); + + py_return = PyRun_String (in_string, Py_single_input, globals, locals); + } + } + + if (locals != NULL + && should_decrement_locals) + Py_XDECREF (locals); + + if (py_return != NULL) + { + switch (return_type) + { + case eScriptReturnTypeCharPtr: // "char *" + { + const char format[3] = "s#"; + success = PyArg_Parse (py_return, format, (char **) ret_value); + break; + } + case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return == Py_None + { + const char format[3] = "z"; + success = PyArg_Parse (py_return, format, (char **) ret_value); + break; + } + case eScriptReturnTypeBool: + { + const char format[2] = "b"; + success = PyArg_Parse (py_return, format, (bool *) ret_value); + break; + } + case eScriptReturnTypeShortInt: + { + const char format[2] = "h"; + success = PyArg_Parse (py_return, format, (short *) ret_value); + break; + } + case eScriptReturnTypeShortIntUnsigned: + { + const char format[2] = "H"; + success = PyArg_Parse (py_return, format, (unsigned short *) ret_value); + break; + } + case eScriptReturnTypeInt: + { + const char format[2] = "i"; + success = PyArg_Parse (py_return, format, (int *) ret_value); + break; + } + case eScriptReturnTypeIntUnsigned: + { + const char format[2] = "I"; + success = PyArg_Parse (py_return, format, (unsigned int *) ret_value); + break; + } + case eScriptReturnTypeLongInt: + { + const char format[2] = "l"; + success = PyArg_Parse (py_return, format, (long *) ret_value); + break; + } + case eScriptReturnTypeLongIntUnsigned: + { + const char format[2] = "k"; + success = PyArg_Parse (py_return, format, (unsigned long *) ret_value); + break; + } + case eScriptReturnTypeLongLong: + { + const char format[2] = "L"; + success = PyArg_Parse (py_return, format, (long long *) ret_value); + break; + } + case eScriptReturnTypeLongLongUnsigned: + { + const char format[2] = "K"; + success = PyArg_Parse (py_return, format, (unsigned long long *) ret_value); + break; + } + case eScriptReturnTypeFloat: + { + const char format[2] = "f"; + success = PyArg_Parse (py_return, format, (float *) ret_value); + break; + } + case eScriptReturnTypeDouble: + { + const char format[2] = "d"; + success = PyArg_Parse (py_return, format, (double *) ret_value); + break; + } + case eScriptReturnTypeChar: + { + const char format[2] = "c"; + success = PyArg_Parse (py_return, format, (char *) ret_value); + break; + } + } + Py_XDECREF (py_return); + if (success) + ret_success = true; + else + ret_success = false; + } + } + + py_error = PyErr_Occurred(); + if (py_error != NULL) + { + ret_success = false; + if (options.GetMaskoutErrors()) + { + if (PyErr_GivenExceptionMatches (py_error, PyExc_SyntaxError)) + PyErr_Print (); + PyErr_Clear(); + } + } + + return ret_success; +} + +bool +ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, const ExecuteScriptOptions &options) +{ + + + Locker locker(this, + ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0), + ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); + + bool success = false; + PyObject *py_return = NULL; + PyObject *mainmod = PyImport_AddModule ("__main__"); + PyObject *globals = PyModule_GetDict (mainmod); + PyObject *locals = NULL; + PyObject *py_error = NULL; + bool should_decrement_locals = false; + + locals = FindSessionDictionary(m_dictionary_name.c_str()); + + if (locals == NULL) + { + locals = PyObject_GetAttrString (globals, m_dictionary_name.c_str()); + should_decrement_locals = true; + } + + if (locals == NULL) + { + locals = globals; + should_decrement_locals = false; + } + + py_error = PyErr_Occurred(); + if (py_error != NULL) + PyErr_Clear(); + + if (in_string != NULL) + { + struct _node *compiled_node = PyParser_SimpleParseString (in_string, Py_file_input); + if (compiled_node) + { + PyCodeObject *compiled_code = PyNode_Compile (compiled_node, "temp.py"); + if (compiled_code) + { + { // scope for PythonInputReaderManager + PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); + py_return = PyEval_EvalCode (compiled_code, globals, locals); + } + if (py_return != NULL) + { + success = true; + Py_XDECREF (py_return); + } + if (locals && should_decrement_locals) + Py_XDECREF (locals); + } + } + } + + py_error = PyErr_Occurred (); + if (py_error != NULL) + { + success = false; + if (options.GetMaskoutErrors()) + { + if (PyErr_GivenExceptionMatches (py_error, PyExc_SyntaxError)) + PyErr_Print (); + PyErr_Clear(); + } + } + + return success; +} + +static const char *g_reader_instructions = "Enter your Python command(s). Type 'DONE' to end."; + +static const char *g_bkpt_command_reader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n" + "def function(frame,bp_loc,internal_dict):\n" + " \"\"\"frame: the SBFrame for the location at which you stopped\n" + " bp_loc: an SBBreakpointLocation for the breakpoint location information\n" + " internal_dict: an LLDB support object not to be used\"\"\""; + +size_t +ScriptInterpreterPython::GenerateBreakpointOptionsCommandCallback +( + void *baton, + InputReader &reader, + InputReaderAction notification, + const char *bytes, + size_t bytes_len +) +{ + static StringList commands_in_progress; + + switch (notification) + { + case eInputReaderActivate: + { + + StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); + bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); + commands_in_progress.Clear(); + if (!batch_mode) + { + out_stream->Printf ("%s\n", g_bkpt_command_reader_instructions); + if (reader.GetPrompt()) + out_stream->Printf ("%s", reader.GetPrompt()); + out_stream->Flush (); + } + } + break; + + case eInputReaderDeactivate: + break; + + case eInputReaderReactivate: + { + StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); + bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); + if (reader.GetPrompt() && !batch_mode) + { + out_stream->Printf ("%s", reader.GetPrompt()); + out_stream->Flush (); + } + } + break; + + case eInputReaderAsynchronousOutputWritten: + break; + + case eInputReaderGotToken: + { + StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); + bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); + std::string temp_string (bytes, bytes_len); + commands_in_progress.AppendString (temp_string.c_str()); + if (!reader.IsDone() && reader.GetPrompt() && !batch_mode) + { + out_stream->Printf ("%s", reader.GetPrompt()); + out_stream->Flush (); + } + } + break; + + case eInputReaderEndOfFile: + case eInputReaderInterrupt: + // Control-c (SIGINT) & control-d both mean finish & exit. + reader.SetIsDone(true); + + // Control-c (SIGINT) ALSO means cancel; do NOT create a breakpoint command. + if (notification == eInputReaderInterrupt) + commands_in_progress.Clear(); + + // Fall through here... + + case eInputReaderDone: + { + bool batch_mode = notification == eInputReaderDone ? + reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode() : + true; + BreakpointOptions *bp_options = (BreakpointOptions *)baton; + std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); + data_ap->user_source.AppendList (commands_in_progress); + if (data_ap.get()) + { + ScriptInterpreter *interpreter = reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); + if (interpreter) + { + if (interpreter->GenerateBreakpointCommandCallbackData (data_ap->user_source, + data_ap->script_source)) + { + BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); + bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp); + } + else if (!batch_mode) + { + StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); + out_stream->Printf ("Warning: No command attached to breakpoint.\n"); + out_stream->Flush(); + } + } + else + { + if (!batch_mode) + { + StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); + out_stream->Printf ("Warning: Unable to find script intepreter; no command attached to breakpoint.\n"); + out_stream->Flush(); + } + } + } + } + break; + + } + + return bytes_len; +} + +size_t +ScriptInterpreterPython::GenerateWatchpointOptionsCommandCallback +( + void *baton, + InputReader &reader, + InputReaderAction notification, + const char *bytes, + size_t bytes_len +) +{ + static StringList commands_in_progress; + + switch (notification) + { + case eInputReaderActivate: + { + StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); + bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); + + commands_in_progress.Clear(); + if (!batch_mode) + { + out_stream->Printf ("%s\n", g_reader_instructions); + if (reader.GetPrompt()) + out_stream->Printf ("%s", reader.GetPrompt()); + out_stream->Flush (); + } + } + break; + + case eInputReaderDeactivate: + break; + + case eInputReaderReactivate: + { + StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); + bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); + if (reader.GetPrompt() && !batch_mode) + { + out_stream->Printf ("%s", reader.GetPrompt()); + out_stream->Flush (); + } + } + break; + + case eInputReaderAsynchronousOutputWritten: + break; + + case eInputReaderGotToken: + { + StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); + bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); + std::string temp_string (bytes, bytes_len); + commands_in_progress.AppendString (temp_string.c_str()); + if (!reader.IsDone() && reader.GetPrompt() && !batch_mode) + { + out_stream->Printf ("%s", reader.GetPrompt()); + out_stream->Flush (); + } + } + break; + + case eInputReaderEndOfFile: + case eInputReaderInterrupt: + // Control-c (SIGINT) & control-d both mean finish & exit. + reader.SetIsDone(true); + + // Control-c (SIGINT) ALSO means cancel; do NOT create a breakpoint command. + if (notification == eInputReaderInterrupt) + commands_in_progress.Clear(); + + // Fall through here... + + case eInputReaderDone: + { + bool batch_mode = notification == eInputReaderDone ? + reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode() : + true; + WatchpointOptions *wp_options = (WatchpointOptions *)baton; + std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData()); + data_ap->user_source.AppendList (commands_in_progress); + if (data_ap.get()) + { + ScriptInterpreter *interpreter = reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); + if (interpreter) + { + if (interpreter->GenerateWatchpointCommandCallbackData (data_ap->user_source, + data_ap->script_source)) + { + BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release())); + wp_options->SetCallback (ScriptInterpreterPython::WatchpointCallbackFunction, baton_sp); + } + else if (!batch_mode) + { + StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); + out_stream->Printf ("Warning: No command attached to breakpoint.\n"); + out_stream->Flush(); + } + } + else + { + if (!batch_mode) + { + StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); + out_stream->Printf ("Warning: Unable to find script intepreter; no command attached to breakpoint.\n"); + out_stream->Flush(); + } + } + } + } + break; + + } + + return bytes_len; +} + +void +ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options, + CommandReturnObject &result) +{ + Debugger &debugger = GetCommandInterpreter().GetDebugger(); + + InputReaderSP reader_sp (new InputReader (debugger)); + + if (reader_sp) + { + Error err = reader_sp->Initialize ( + ScriptInterpreterPython::GenerateBreakpointOptionsCommandCallback, + bp_options, // baton + eInputReaderGranularityLine, // token size, for feeding data to callback function + "DONE", // end token + " ", // prompt + true); // echo input + + if (err.Success()) + debugger.PushInputReader (reader_sp); + else + { + result.AppendError (err.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendError("out of memory"); + result.SetStatus (eReturnStatusFailed); + } +} + +void +ScriptInterpreterPython::CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options, + CommandReturnObject &result) +{ + Debugger &debugger = GetCommandInterpreter().GetDebugger(); + + InputReaderSP reader_sp (new InputReader (debugger)); + + if (reader_sp) + { + Error err = reader_sp->Initialize ( + ScriptInterpreterPython::GenerateWatchpointOptionsCommandCallback, + wp_options, // baton + eInputReaderGranularityLine, // token size, for feeding data to callback function + "DONE", // end token + "> ", // prompt + true); // echo input + + if (err.Success()) + debugger.PushInputReader (reader_sp); + else + { + result.AppendError (err.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendError("out of memory"); + result.SetStatus (eReturnStatusFailed); + } +} + +// Set a Python one-liner as the callback for the breakpoint. +void +ScriptInterpreterPython::SetBreakpointCommandCallback (BreakpointOptions *bp_options, + const char *oneliner) +{ + std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); + + // It's necessary to set both user_source and script_source to the oneliner. + // The former is used to generate callback description (as in breakpoint command list) + // while the latter is used for Python to interpret during the actual callback. + + data_ap->user_source.AppendString (oneliner); + data_ap->script_source.assign (oneliner); + + if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source)) + { + BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); + bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp); + } + + return; +} + +// Set a Python one-liner as the callback for the watchpoint. +void +ScriptInterpreterPython::SetWatchpointCommandCallback (WatchpointOptions *wp_options, + const char *oneliner) +{ + std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData()); + + // It's necessary to set both user_source and script_source to the oneliner. + // The former is used to generate callback description (as in watchpoint command list) + // while the latter is used for Python to interpret during the actual callback. + + data_ap->user_source.AppendString (oneliner); + data_ap->script_source.assign (oneliner); + + if (GenerateWatchpointCommandCallbackData (data_ap->user_source, data_ap->script_source)) + { + BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release())); + wp_options->SetCallback (ScriptInterpreterPython::WatchpointCallbackFunction, baton_sp); + } + + return; +} + +bool +ScriptInterpreterPython::ExportFunctionDefinitionToInterpreter (StringList &function_def) +{ + // Convert StringList to one long, newline delimited, const char *. + std::string function_def_string(function_def.CopyList()); + + return ExecuteMultipleLines (function_def_string.c_str(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false)); +} + +bool +ScriptInterpreterPython::GenerateFunction(const char *signature, const StringList &input) +{ + int num_lines = input.GetSize (); + if (num_lines == 0) + return false; + + if (!signature || *signature == 0) + return false; + + StreamString sstr; + StringList auto_generated_function; + auto_generated_function.AppendString (signature); + auto_generated_function.AppendString (" global_dict = globals()"); // Grab the global dictionary + auto_generated_function.AppendString (" new_keys = internal_dict.keys()"); // Make a list of keys in the session dict + auto_generated_function.AppendString (" old_keys = global_dict.keys()"); // Save list of keys in global dict + auto_generated_function.AppendString (" global_dict.update (internal_dict)"); // Add the session dictionary to the + // global dictionary. + + // Wrap everything up inside the function, increasing the indentation. + + auto_generated_function.AppendString(" if True:"); + for (int i = 0; i < num_lines; ++i) + { + sstr.Clear (); + sstr.Printf (" %s", input.GetStringAtIndex (i)); + auto_generated_function.AppendString (sstr.GetData()); + } + auto_generated_function.AppendString (" for key in new_keys:"); // Iterate over all the keys from session dict + auto_generated_function.AppendString (" internal_dict[key] = global_dict[key]"); // Update session dict values + auto_generated_function.AppendString (" if key not in old_keys:"); // If key was not originally in global dict + auto_generated_function.AppendString (" del global_dict[key]"); // ...then remove key/value from global dict + + // Verify that the results are valid Python. + + if (!ExportFunctionDefinitionToInterpreter (auto_generated_function)) + return false; + + return true; + +} + +bool +ScriptInterpreterPython::GenerateTypeScriptFunction (StringList &user_input, std::string& output, void* name_token) +{ + static uint32_t num_created_functions = 0; + user_input.RemoveBlankLines (); + StreamString sstr; + + // Check to see if we have any data; if not, just return. + if (user_input.GetSize() == 0) + return false; + + // Take what the user wrote, wrap it all up inside one big auto-generated Python function, passing in the + // ValueObject as parameter to the function. + + std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_type_print_func", num_created_functions, name_token)); + sstr.Printf ("def %s (valobj, internal_dict):", auto_generated_function_name.c_str()); + + if (!GenerateFunction(sstr.GetData(), user_input)) + return false; + + // Store the name of the auto-generated function to be called. + output.assign(auto_generated_function_name); + return true; +} + +bool +ScriptInterpreterPython::GenerateScriptAliasFunction (StringList &user_input, std::string &output) +{ + static uint32_t num_created_functions = 0; + user_input.RemoveBlankLines (); + StreamString sstr; + + // Check to see if we have any data; if not, just return. + if (user_input.GetSize() == 0) + return false; + + std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_cmd_alias_func", num_created_functions)); + + sstr.Printf ("def %s (debugger, args, result, internal_dict):", auto_generated_function_name.c_str()); + + if (!GenerateFunction(sstr.GetData(),user_input)) + return false; + + // Store the name of the auto-generated function to be called. + output.assign(auto_generated_function_name); + return true; +} + + +bool +ScriptInterpreterPython::GenerateTypeSynthClass (StringList &user_input, std::string &output, void* name_token) +{ + static uint32_t num_created_classes = 0; + user_input.RemoveBlankLines (); + int num_lines = user_input.GetSize (); + StreamString sstr; + + // Check to see if we have any data; if not, just return. + if (user_input.GetSize() == 0) + return false; + + // Wrap all user input into a Python class + + std::string auto_generated_class_name(GenerateUniqueName("lldb_autogen_python_type_synth_class",num_created_classes,name_token)); + + StringList auto_generated_class; + + // Create the function name & definition string. + + sstr.Printf ("class %s:", auto_generated_class_name.c_str()); + auto_generated_class.AppendString (sstr.GetData()); + + // Wrap everything up inside the class, increasing the indentation. + // we don't need to play any fancy indentation tricks here because there is no + // surrounding code whose indentation we need to honor + for (int i = 0; i < num_lines; ++i) + { + sstr.Clear (); + sstr.Printf (" %s", user_input.GetStringAtIndex (i)); + auto_generated_class.AppendString (sstr.GetData()); + } + + + // Verify that the results are valid Python. + // (even though the method is ExportFunctionDefinitionToInterpreter, a class will actually be exported) + // (TODO: rename that method to ExportDefinitionToInterpreter) + if (!ExportFunctionDefinitionToInterpreter (auto_generated_class)) + return false; + + // Store the name of the auto-generated class + + output.assign(auto_generated_class_name); + return true; +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::OSPlugin_CreatePluginObject (const char *class_name, lldb::ProcessSP process_sp) +{ + if (class_name == NULL || class_name[0] == '\0') + return lldb::ScriptInterpreterObjectSP(); + + if (!process_sp) + return lldb::ScriptInterpreterObjectSP(); + + void* ret_val; + + { + Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock); + ret_val = g_swig_create_os_plugin (class_name, + m_dictionary_name.c_str(), + process_sp); + } + + return MakeScriptObject(ret_val); +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) +{ + Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock); + + static char callee_name[] = "get_register_info"; + + if (!os_plugin_object_sp) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject(); + + if (implementor == NULL || implementor == Py_None) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + if (pmeth == NULL || pmeth == Py_None) + { + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyCallable_Check(pmeth) == 0) + { + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + + // right now we know this function exists and is callable.. + PyObject* py_return = PyObject_CallMethod(implementor, callee_name, NULL); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) + { + PyErr_Print(); + PyErr_Clear(); + } + + return MakeScriptObject(py_return); +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) +{ + Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock); + + static char callee_name[] = "get_thread_info"; + + if (!os_plugin_object_sp) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject(); + + if (implementor == NULL || implementor == Py_None) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + if (pmeth == NULL || pmeth == Py_None) + { + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyCallable_Check(pmeth) == 0) + { + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + + // right now we know this function exists and is callable.. + PyObject* py_return = PyObject_CallMethod(implementor, callee_name, NULL); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) + { + PyErr_Print(); + PyErr_Clear(); + } + + return MakeScriptObject(py_return); +} + +// GetPythonValueFormatString provides a system independent type safe way to +// convert a variable's type into a python value format. Python value formats +// are defined in terms of builtin C types and could change from system to +// as the underlying typedef for uint* types, size_t, off_t and other values +// change. + +template <typename T> +const char *GetPythonValueFormatString(T t) +{ + assert(!"Unhandled type passed to GetPythonValueFormatString(T), make a specialization of GetPythonValueFormatString() to support this type."); + return NULL; +} +template <> const char *GetPythonValueFormatString (char *) { return "s"; } +template <> const char *GetPythonValueFormatString (char) { return "b"; } +template <> const char *GetPythonValueFormatString (unsigned char) { return "B"; } +template <> const char *GetPythonValueFormatString (short) { return "h"; } +template <> const char *GetPythonValueFormatString (unsigned short) { return "H"; } +template <> const char *GetPythonValueFormatString (int) { return "i"; } +template <> const char *GetPythonValueFormatString (unsigned int) { return "I"; } +template <> const char *GetPythonValueFormatString (long) { return "l"; } +template <> const char *GetPythonValueFormatString (unsigned long) { return "k"; } +template <> const char *GetPythonValueFormatString (long long) { return "L"; } +template <> const char *GetPythonValueFormatString (unsigned long long) { return "K"; } +template <> const char *GetPythonValueFormatString (float t) { return "f"; } +template <> const char *GetPythonValueFormatString (double t) { return "d"; } + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::OSPlugin_RegisterContextData (lldb::ScriptInterpreterObjectSP os_plugin_object_sp, + lldb::tid_t tid) +{ + Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock); + + static char callee_name[] = "get_register_data"; + static char *param_format = const_cast<char *>(GetPythonValueFormatString(tid)); + + if (!os_plugin_object_sp) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject(); + + if (implementor == NULL || implementor == Py_None) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + if (pmeth == NULL || pmeth == Py_None) + { + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyCallable_Check(pmeth) == 0) + { + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + + // right now we know this function exists and is callable.. + PyObject* py_return = PyObject_CallMethod(implementor, callee_name, param_format, tid); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) + { + PyErr_Print(); + PyErr_Clear(); + } + + return MakeScriptObject(py_return); +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP os_plugin_object_sp, + lldb::tid_t tid, + lldb::addr_t context) +{ + Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock); + + static char callee_name[] = "create_thread"; + std::string param_format; + param_format += GetPythonValueFormatString(tid); + param_format += GetPythonValueFormatString(context); + + if (!os_plugin_object_sp) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject(); + + if (implementor == NULL || implementor == Py_None) + return lldb::ScriptInterpreterObjectSP(); + + PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name); + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + if (pmeth == NULL || pmeth == Py_None) + { + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyCallable_Check(pmeth) == 0) + { + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + return lldb::ScriptInterpreterObjectSP(); + } + + if (PyErr_Occurred()) + { + PyErr_Clear(); + } + + Py_XDECREF(pmeth); + + // right now we know this function exists and is callable.. + PyObject* py_return = PyObject_CallMethod(implementor, callee_name, ¶m_format[0], tid, context); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) + { + PyErr_Print(); + PyErr_Clear(); + } + + return MakeScriptObject(py_return); +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::CreateSyntheticScriptedProvider (const char *class_name, + lldb::ValueObjectSP valobj) +{ + if (class_name == NULL || class_name[0] == '\0') + return lldb::ScriptInterpreterObjectSP(); + + if (!valobj.get()) + return lldb::ScriptInterpreterObjectSP(); + + ExecutionContext exe_ctx (valobj->GetExecutionContextRef()); + Target *target = exe_ctx.GetTargetPtr(); + + if (!target) + return lldb::ScriptInterpreterObjectSP(); + + Debugger &debugger = target->GetDebugger(); + ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); + ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter; + + if (!script_interpreter) + return lldb::ScriptInterpreterObjectSP(); + + void* ret_val; + + { + Locker py_lock(this); + ret_val = g_swig_synthetic_script (class_name, + python_interpreter->m_dictionary_name.c_str(), + valobj); + } + + return MakeScriptObject(ret_val); +} + +bool +ScriptInterpreterPython::GenerateTypeScriptFunction (const char* oneliner, std::string& output, void* name_token) +{ + StringList input; + input.SplitIntoLines(oneliner, strlen(oneliner)); + return GenerateTypeScriptFunction(input, output, name_token); +} + +bool +ScriptInterpreterPython::GenerateTypeSynthClass (const char* oneliner, std::string& output, void* name_token) +{ + StringList input; + input.SplitIntoLines(oneliner, strlen(oneliner)); + return GenerateTypeSynthClass(input, output, name_token); +} + + +bool +ScriptInterpreterPython::GenerateBreakpointCommandCallbackData (StringList &user_input, std::string& output) +{ + static uint32_t num_created_functions = 0; + user_input.RemoveBlankLines (); + StreamString sstr; + + if (user_input.GetSize() == 0) + return false; + + std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_bp_callback_func_",num_created_functions)); + sstr.Printf ("def %s (frame, bp_loc, internal_dict):", auto_generated_function_name.c_str()); + + if (!GenerateFunction(sstr.GetData(), user_input)) + return false; + + // Store the name of the auto-generated function to be called. + output.assign(auto_generated_function_name); + return true; +} + +bool +ScriptInterpreterPython::GenerateWatchpointCommandCallbackData (StringList &user_input, std::string& output) +{ + static uint32_t num_created_functions = 0; + user_input.RemoveBlankLines (); + StreamString sstr; + + if (user_input.GetSize() == 0) + return false; + + std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_wp_callback_func_",num_created_functions)); + sstr.Printf ("def %s (frame, wp, internal_dict):", auto_generated_function_name.c_str()); + + if (!GenerateFunction(sstr.GetData(), user_input)) + return false; + + // Store the name of the auto-generated function to be called. + output.assign(auto_generated_function_name); + return true; +} + +bool +ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name, + lldb::ValueObjectSP valobj, + lldb::ScriptInterpreterObjectSP& callee_wrapper_sp, + std::string& retval) +{ + + Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); + + if (!valobj.get()) + { + retval.assign("<no object>"); + return false; + } + + void* old_callee = (callee_wrapper_sp ? callee_wrapper_sp->GetObject() : NULL); + void* new_callee = old_callee; + + bool ret_val; + if (python_function_name + && *python_function_name) + { + { + Locker py_lock(this); + { + Timer scoped_timer ("g_swig_typescript_callback","g_swig_typescript_callback"); + ret_val = g_swig_typescript_callback (python_function_name, + FindSessionDictionary(m_dictionary_name.c_str()), + valobj, + &new_callee, + retval); + } + } + } + else + { + retval.assign("<no function name>"); + return false; + } + + if (new_callee && old_callee != new_callee) + callee_wrapper_sp = MakeScriptObject(new_callee); + + return ret_val; + +} + +bool +ScriptInterpreterPython::BreakpointCallbackFunction +( + void *baton, + StoppointCallbackContext *context, + user_id_t break_id, + user_id_t break_loc_id +) +{ + BreakpointOptions::CommandData *bp_option_data = (BreakpointOptions::CommandData *) baton; + const char *python_function_name = bp_option_data->script_source.c_str(); + + if (!context) + return true; + + ExecutionContext exe_ctx (context->exe_ctx_ref); + Target *target = exe_ctx.GetTargetPtr(); + + if (!target) + return true; + + Debugger &debugger = target->GetDebugger(); + ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); + ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter; + + if (!script_interpreter) + return true; + + if (python_function_name != NULL + && python_function_name[0] != '\0') + { + const StackFrameSP stop_frame_sp (exe_ctx.GetFrameSP()); + BreakpointSP breakpoint_sp = target->GetBreakpointByID (break_id); + if (breakpoint_sp) + { + const BreakpointLocationSP bp_loc_sp (breakpoint_sp->FindLocationByID (break_loc_id)); + + if (stop_frame_sp && bp_loc_sp) + { + bool ret_val = true; + { + Locker py_lock(python_interpreter); + ret_val = g_swig_breakpoint_callback (python_function_name, + python_interpreter->m_dictionary_name.c_str(), + stop_frame_sp, + bp_loc_sp); + } + return ret_val; + } + } + } + // We currently always true so we stop in case anything goes wrong when + // trying to call the script function + return true; +} + +bool +ScriptInterpreterPython::WatchpointCallbackFunction +( + void *baton, + StoppointCallbackContext *context, + user_id_t watch_id +) +{ + WatchpointOptions::CommandData *wp_option_data = (WatchpointOptions::CommandData *) baton; + const char *python_function_name = wp_option_data->script_source.c_str(); + + if (!context) + return true; + + ExecutionContext exe_ctx (context->exe_ctx_ref); + Target *target = exe_ctx.GetTargetPtr(); + + if (!target) + return true; + + Debugger &debugger = target->GetDebugger(); + ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); + ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter; + + if (!script_interpreter) + return true; + + if (python_function_name != NULL + && python_function_name[0] != '\0') + { + const StackFrameSP stop_frame_sp (exe_ctx.GetFrameSP()); + WatchpointSP wp_sp = target->GetWatchpointList().FindByID (watch_id); + if (wp_sp) + { + if (stop_frame_sp && wp_sp) + { + bool ret_val = true; + { + Locker py_lock(python_interpreter); + ret_val = g_swig_watchpoint_callback (python_function_name, + python_interpreter->m_dictionary_name.c_str(), + stop_frame_sp, + wp_sp); + } + return ret_val; + } + } + } + // We currently always true so we stop in case anything goes wrong when + // trying to call the script function + return true; +} + +lldb::thread_result_t +ScriptInterpreterPython::RunEmbeddedPythonInterpreter (lldb::thread_arg_t baton) +{ + ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton; + + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); + + if (log) + log->Printf ("%p ScriptInterpreterPython::RunEmbeddedPythonInterpreter () thread starting...", baton); + + char error_str[1024]; + const char *pty_slave_name = script_interpreter->m_embedded_python_pty.GetSlaveName (error_str, sizeof (error_str)); + + if (pty_slave_name != NULL) + { + StreamString run_string; + + // Ensure we have the GIL before running any Python code. + // Since we're only running a few one-liners and then dropping to the interpreter (which will release the GIL when needed), + // we can just release the GIL after finishing our work. + // If finer-grained locking is desirable, we can lock and unlock the GIL only when calling a python function. + Locker locker(script_interpreter, + ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | ScriptInterpreterPython::Locker::InitGlobals, + ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); + + run_string.Printf ("run_one_line (%s, 'save_stderr = sys.stderr')", script_interpreter->m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear (); + + run_string.Printf ("run_one_line (%s, 'sys.stderr = sys.stdout')", script_interpreter->m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear (); + + run_string.Printf ("run_one_line (%s, 'save_stdin = sys.stdin')", script_interpreter->m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear (); + + run_string.Printf ("run_one_line (%s, \"sys.stdin = open ('%s', 'r')\")", script_interpreter->m_dictionary_name.c_str(), + pty_slave_name); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear (); + + // The following call drops into the embedded interpreter loop and stays there until the + // user chooses to exit from the Python interpreter. + // This embedded interpreter will, as any Python code that performs I/O, unlock the GIL before + // a system call that can hang, and lock it when the syscall has returned. + + // We need to surround the call to the embedded interpreter with calls to PyGILState_Ensure and + // PyGILState_Release (using the Locker above). This is because Python has a global lock which must be held whenever we want + // to touch any Python objects. Otherwise, if the user calls Python code, the interpreter state will be off, + // and things could hang (it's happened before). + + run_string.Printf ("run_python_interpreter (%s)", script_interpreter->m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear (); + + run_string.Printf ("run_one_line (%s, 'sys.stdin = save_stdin')", script_interpreter->m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear(); + + run_string.Printf ("run_one_line (%s, 'sys.stderr = save_stderr')", script_interpreter->m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear(); + } + + if (script_interpreter->m_embedded_python_input_reader_sp) + script_interpreter->m_embedded_python_input_reader_sp->SetIsDone (true); + + script_interpreter->m_embedded_python_pty.CloseSlaveFileDescriptor(); + + log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT); + if (log) + log->Printf ("%p ScriptInterpreterPython::RunEmbeddedPythonInterpreter () thread exiting...", baton); + + + // Clean up the input reader and make the debugger pop it off the stack. + Debugger &debugger = script_interpreter->GetCommandInterpreter().GetDebugger(); + const InputReaderSP reader_sp = script_interpreter->m_embedded_python_input_reader_sp; + if (reader_sp) + { + debugger.PopInputReader (reader_sp); + script_interpreter->m_embedded_python_input_reader_sp.reset(); + } + + return NULL; +} + +lldb::thread_result_t +ScriptInterpreterPython::PythonInputReaderManager::RunPythonInputReader (lldb::thread_arg_t baton) +{ + ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton; + + const InputReaderSP reader_sp = script_interpreter->m_embedded_thread_input_reader_sp; + + if (reader_sp) + reader_sp->WaitOnReaderIsDone(); + + return NULL; +} + +size_t +ScriptInterpreterPython::CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor_sp) +{ + if (!implementor_sp) + return 0; + + void* implementor = implementor_sp->GetObject(); + + if (!implementor) + return 0; + + if (!g_swig_calc_children) + return 0; + + uint32_t ret_val = 0; + + { + Locker py_lock(this); + ret_val = g_swig_calc_children (implementor); + } + + return ret_val; +} + +lldb::ValueObjectSP +ScriptInterpreterPython::GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& implementor_sp, uint32_t idx) +{ + if (!implementor_sp) + return lldb::ValueObjectSP(); + + void* implementor = implementor_sp->GetObject(); + + if (!implementor) + return lldb::ValueObjectSP(); + + if (!g_swig_get_child_index || !g_swig_cast_to_sbvalue) + return lldb::ValueObjectSP(); + + void* child_ptr = NULL; + lldb::SBValue* value_sb = NULL; + lldb::ValueObjectSP ret_val; + + { + Locker py_lock(this); + child_ptr = g_swig_get_child_index (implementor,idx); + if (child_ptr != NULL && child_ptr != Py_None) + { + value_sb = (lldb::SBValue*)g_swig_cast_to_sbvalue(child_ptr); + if (value_sb == NULL) + Py_XDECREF(child_ptr); + else + ret_val = value_sb->GetSP(); + } + else + { + Py_XDECREF(child_ptr); + } + } + + return ret_val; +} + +int +ScriptInterpreterPython::GetIndexOfChildWithName (const lldb::ScriptInterpreterObjectSP& implementor_sp, const char* child_name) +{ + if (!implementor_sp) + return UINT32_MAX; + + void* implementor = implementor_sp->GetObject(); + + if (!implementor) + return UINT32_MAX; + + if (!g_swig_get_index_child) + return UINT32_MAX; + + int ret_val = UINT32_MAX; + + { + Locker py_lock(this); + ret_val = g_swig_get_index_child (implementor, child_name); + } + + return ret_val; +} + +bool +ScriptInterpreterPython::UpdateSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor_sp) +{ + bool ret_val = false; + + if (!implementor_sp) + return ret_val; + + void* implementor = implementor_sp->GetObject(); + + if (!implementor) + return ret_val; + + if (!g_swig_update_provider) + return ret_val; + + { + Locker py_lock(this); + ret_val = g_swig_update_provider (implementor); + } + + return ret_val; +} + +bool +ScriptInterpreterPython::MightHaveChildrenSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor_sp) +{ + bool ret_val = false; + + if (!implementor_sp) + return ret_val; + + void* implementor = implementor_sp->GetObject(); + + if (!implementor) + return ret_val; + + if (!g_swig_mighthavechildren_provider) + return ret_val; + + { + Locker py_lock(this); + ret_val = g_swig_mighthavechildren_provider (implementor); + } + + return ret_val; +} + +static std::string +ReadPythonBacktrace (PyObject* py_backtrace) +{ + PyObject* traceback_module = NULL, + *stringIO_module = NULL, + *stringIO_builder = NULL, + *stringIO_buffer = NULL, + *printTB = NULL, + *printTB_args = NULL, + *printTB_result = NULL, + *stringIO_getvalue = NULL, + *printTB_string = NULL; + + std::string retval("backtrace unavailable"); + + if (py_backtrace && py_backtrace != Py_None) + { + traceback_module = PyImport_ImportModule("traceback"); + stringIO_module = PyImport_ImportModule("StringIO"); + + if (traceback_module && traceback_module != Py_None && stringIO_module && stringIO_module != Py_None) + { + stringIO_builder = PyObject_GetAttrString(stringIO_module, "StringIO"); + if (stringIO_builder && stringIO_builder != Py_None) + { + stringIO_buffer = PyObject_CallObject(stringIO_builder, NULL); + if (stringIO_buffer && stringIO_buffer != Py_None) + { + printTB = PyObject_GetAttrString(traceback_module, "print_tb"); + if (printTB && printTB != Py_None) + { + printTB_args = Py_BuildValue("OOO",py_backtrace,Py_None,stringIO_buffer); + printTB_result = PyObject_CallObject(printTB, printTB_args); + stringIO_getvalue = PyObject_GetAttrString(stringIO_buffer, "getvalue"); + if (stringIO_getvalue && stringIO_getvalue != Py_None) + { + printTB_string = PyObject_CallObject (stringIO_getvalue,NULL); + if (printTB_string && printTB_string != Py_None && PyString_Check(printTB_string)) + retval.assign(PyString_AsString(printTB_string)); + } + } + } + } + } + } + Py_XDECREF(traceback_module); + Py_XDECREF(stringIO_module); + Py_XDECREF(stringIO_builder); + Py_XDECREF(stringIO_buffer); + Py_XDECREF(printTB); + Py_XDECREF(printTB_args); + Py_XDECREF(printTB_result); + Py_XDECREF(stringIO_getvalue); + Py_XDECREF(printTB_string); + return retval; +} + +bool +ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, + Process* process, + std::string& output, + Error& error) +{ + bool ret_val; + if (!process) + { + error.SetErrorString("no process"); + return false; + } + if (!impl_function || !impl_function[0]) + { + error.SetErrorString("no function to execute"); + return false; + } + if (!g_swig_run_script_keyword_process) + { + error.SetErrorString("internal helper function missing"); + return false; + } + { + ProcessSP process_sp(process->shared_from_this()); + Locker py_lock(this); + ret_val = g_swig_run_script_keyword_process (impl_function, m_dictionary_name.c_str(), process_sp, output); + if (!ret_val) + error.SetErrorString("python script evaluation failed"); + } + return ret_val; +} + +bool +ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, + Thread* thread, + std::string& output, + Error& error) +{ + bool ret_val; + if (!thread) + { + error.SetErrorString("no thread"); + return false; + } + if (!impl_function || !impl_function[0]) + { + error.SetErrorString("no function to execute"); + return false; + } + if (!g_swig_run_script_keyword_thread) + { + error.SetErrorString("internal helper function missing"); + return false; + } + { + ThreadSP thread_sp(thread->shared_from_this()); + Locker py_lock(this); + ret_val = g_swig_run_script_keyword_thread (impl_function, m_dictionary_name.c_str(), thread_sp, output); + if (!ret_val) + error.SetErrorString("python script evaluation failed"); + } + return ret_val; +} + +bool +ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, + Target* target, + std::string& output, + Error& error) +{ + bool ret_val; + if (!target) + { + error.SetErrorString("no thread"); + return false; + } + if (!impl_function || !impl_function[0]) + { + error.SetErrorString("no function to execute"); + return false; + } + if (!g_swig_run_script_keyword_target) + { + error.SetErrorString("internal helper function missing"); + return false; + } + { + TargetSP target_sp(target->shared_from_this()); + Locker py_lock(this); + ret_val = g_swig_run_script_keyword_target (impl_function, m_dictionary_name.c_str(), target_sp, output); + if (!ret_val) + error.SetErrorString("python script evaluation failed"); + } + return ret_val; +} + +bool +ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, + StackFrame* frame, + std::string& output, + Error& error) +{ + bool ret_val; + if (!frame) + { + error.SetErrorString("no frame"); + return false; + } + if (!impl_function || !impl_function[0]) + { + error.SetErrorString("no function to execute"); + return false; + } + if (!g_swig_run_script_keyword_frame) + { + error.SetErrorString("internal helper function missing"); + return false; + } + { + StackFrameSP frame_sp(frame->shared_from_this()); + Locker py_lock(this); + ret_val = g_swig_run_script_keyword_frame (impl_function, m_dictionary_name.c_str(), frame_sp, output); + if (!ret_val) + error.SetErrorString("python script evaluation failed"); + } + return ret_val; +} + +uint64_t replace_all(std::string& str, const std::string& oldStr, const std::string& newStr) +{ + size_t pos = 0; + uint64_t matches = 0; + while((pos = str.find(oldStr, pos)) != std::string::npos) + { + matches++; + str.replace(pos, oldStr.length(), newStr); + pos += newStr.length(); + } + return matches; +} + +bool +ScriptInterpreterPython::LoadScriptingModule (const char* pathname, + bool can_reload, + bool init_session, + lldb_private::Error& error) +{ + if (!pathname || !pathname[0]) + { + error.SetErrorString("invalid pathname"); + return false; + } + + if (!g_swig_call_module_init) + { + error.SetErrorString("internal helper function missing"); + return false; + } + + lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().shared_from_this(); + + { + FileSpec target_file(pathname, true); + std::string basename(target_file.GetFilename().GetCString()); + + StreamString command_stream; + + // Before executing Pyton code, lock the GIL. + Locker py_lock (this, + Locker::AcquireLock | (init_session ? Locker::InitSession : 0), + Locker::FreeAcquiredLock | (init_session ? Locker::TearDownSession : 0)); + + if (target_file.GetFileType() == FileSpec::eFileTypeInvalid || + target_file.GetFileType() == FileSpec::eFileTypeUnknown) + { + // if not a valid file of any sort, check if it might be a filename still + // dot can't be used but / and \ can, and if either is found, reject + if (strchr(pathname,'\\') || strchr(pathname,'/')) + { + error.SetErrorString("invalid pathname"); + return false; + } + basename = pathname; // not a filename, probably a package of some sort, let it go through + } + else if (target_file.GetFileType() == FileSpec::eFileTypeDirectory || + target_file.GetFileType() == FileSpec::eFileTypeRegular || + target_file.GetFileType() == FileSpec::eFileTypeSymbolicLink) + { + std::string directory(target_file.GetDirectory().GetCString()); + replace_all(directory,"'","\\'"); + + // now make sure that Python has "directory" in the search path + StreamString command_stream; + command_stream.Printf("if not (sys.path.__contains__('%s')):\n sys.path.insert(1,'%s');\n\n", + directory.c_str(), + directory.c_str()); + bool syspath_retval = ExecuteMultipleLines(command_stream.GetData(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)); + if (!syspath_retval) + { + error.SetErrorString("Python sys.path handling failed"); + return false; + } + + // strip .py or .pyc extension + ConstString extension = target_file.GetFileNameExtension(); + if (extension) + { + if (::strcmp(extension.GetCString(), "py") == 0) + basename.resize(basename.length()-3); + else if(::strcmp(extension.GetCString(), "pyc") == 0) + basename.resize(basename.length()-4); + } + } + else + { + error.SetErrorString("no known way to import this module specification"); + return false; + } + + // check if the module is already import-ed + command_stream.Clear(); + command_stream.Printf("sys.modules.__contains__('%s')",basename.c_str()); + bool does_contain = false; + int refcount = 0; + // this call will succeed if the module was ever imported in any Debugger in the lifetime of the process + // in which this LLDB framework is living + bool was_imported_globally = (ExecuteOneLineWithReturn(command_stream.GetData(), + ScriptInterpreterPython::eScriptReturnTypeBool, + &does_contain, + ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)) && does_contain); + // this call will fail if the module was not imported in this Debugger before + command_stream.Clear(); + command_stream.Printf("sys.getrefcount(%s)",basename.c_str()); + bool was_imported_locally = (ExecuteOneLineWithReturn(command_stream.GetData(), + ScriptInterpreterPython::eScriptReturnTypeInt, + &refcount, + ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)) && refcount > 0); + + bool was_imported = (was_imported_globally || was_imported_locally); + + if (was_imported == true && can_reload == false) + { + error.SetErrorString("module already imported"); + return false; + } + + // now actually do the import + command_stream.Clear(); + + if (was_imported) + { + if (!was_imported_locally) + command_stream.Printf("import %s ; reload(%s)",basename.c_str(),basename.c_str()); + else + command_stream.Printf("reload(%s)",basename.c_str()); + } + else + command_stream.Printf("import %s",basename.c_str()); + + bool import_retval = ExecuteMultipleLines(command_stream.GetData(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false).SetMaskoutErrors(false)); + PyObject* py_error = PyErr_Occurred(); // per Python docs: "you do not need to Py_DECREF()" the return of this function + + if (py_error || !import_retval) // check for failure of the import + { + if (py_error) // if we have a Python error.. + { + PyObject *type = NULL,*value = NULL,*traceback = NULL; + PyErr_Fetch (&type,&value,&traceback); + + if (PyErr_GivenExceptionMatches (py_error, PyExc_ImportError)) // and it is an ImportError + { + if (value && value != Py_None) + error.SetErrorString(PyString_AsString(PyObject_Str(value))); + else + error.SetErrorString("ImportError raised by imported module"); + } + else // any other error + { + // get the backtrace + std::string bt = ReadPythonBacktrace(traceback); + + if (value && value != Py_None) + error.SetErrorStringWithFormat("Python error raised while importing module: %s - traceback: %s", PyString_AsString(PyObject_Str(value)),bt.c_str()); + else + error.SetErrorStringWithFormat("Python raised an error while importing module - traceback: %s",bt.c_str()); + } + + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + } + else // we failed but have no error to explain why + { + error.SetErrorString("unknown error while importing module"); + } + + // anyway, clear the error indicator and return false + PyErr_Clear(); + return false; + } + + // if we are here, everything worked + // call __lldb_init_module(debugger,dict) + if (!g_swig_call_module_init (basename.c_str(), + m_dictionary_name.c_str(), + debugger_sp)) + { + error.SetErrorString("calling __lldb_init_module failed"); + return false; + } + return true; + } +} + +lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::MakeScriptObject (void* object) +{ + return lldb::ScriptInterpreterObjectSP(new ScriptInterpreterPythonObject(object)); +} + +ScriptInterpreterPython::SynchronicityHandler::SynchronicityHandler (lldb::DebuggerSP debugger_sp, + ScriptedCommandSynchronicity synchro) : + m_debugger_sp(debugger_sp), + m_synch_wanted(synchro), + m_old_asynch(debugger_sp->GetAsyncExecution()) +{ + if (m_synch_wanted == eScriptedCommandSynchronicitySynchronous) + m_debugger_sp->SetAsyncExecution(false); + else if (m_synch_wanted == eScriptedCommandSynchronicityAsynchronous) + m_debugger_sp->SetAsyncExecution(true); +} + +ScriptInterpreterPython::SynchronicityHandler::~SynchronicityHandler() +{ + if (m_synch_wanted != eScriptedCommandSynchronicityCurrentValue) + m_debugger_sp->SetAsyncExecution(m_old_asynch); +} + +bool +ScriptInterpreterPython::RunScriptBasedCommand(const char* impl_function, + const char* args, + ScriptedCommandSynchronicity synchronicity, + lldb_private::CommandReturnObject& cmd_retobj, + Error& error) +{ + if (!impl_function) + { + error.SetErrorString("no function to execute"); + return false; + } + + if (!g_swig_call_command) + { + error.SetErrorString("no helper function to run scripted commands"); + return false; + } + + lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().shared_from_this(); + + if (!debugger_sp.get()) + { + error.SetErrorString("invalid Debugger pointer"); + return false; + } + + bool ret_val = false; + + std::string err_msg; + + { + Locker py_lock(this, + Locker::AcquireLock | Locker::InitSession, + Locker::FreeLock | Locker::TearDownSession); + + SynchronicityHandler synch_handler(debugger_sp, + synchronicity); + + // we need to save the thread state when we first start the command + // because we might decide to interrupt it while some action is taking + // place outside of Python (e.g. printing to screen, waiting for the network, ...) + // in that case, _PyThreadState_Current will be NULL - and we would be unable + // to set the asynchronous exception - not a desirable situation + m_command_thread_state = _PyThreadState_Current; + + PythonInputReaderManager py_input(this); + + ret_val = g_swig_call_command (impl_function, + m_dictionary_name.c_str(), + debugger_sp, + args, + cmd_retobj); + } + + if (!ret_val) + error.SetErrorString("unable to execute script function"); + else + error.Clear(); + + return ret_val; +} + +// in Python, a special attribute __doc__ contains the docstring +// for an object (function, method, class, ...) if any is defined +// Otherwise, the attribute's value is None +bool +ScriptInterpreterPython::GetDocumentationForItem(const char* item, std::string& dest) +{ + dest.clear(); + if (!item || !*item) + return false; + std::string command(item); + command += ".__doc__"; + + char* result_ptr = NULL; // Python is going to point this to valid data if ExecuteOneLineWithReturn returns successfully + + if (ExecuteOneLineWithReturn (command.c_str(), + ScriptInterpreter::eScriptReturnTypeCharStrOrNone, + &result_ptr, + ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false))) + { + if (result_ptr) + dest.assign(result_ptr); + return true; + } + else + { + StreamString str_stream; + str_stream.Printf("Function %s was not found. Containing module might be missing.",item); + dest.assign(str_stream.GetData()); + return false; + } +} + +std::unique_ptr<ScriptInterpreterLocker> +ScriptInterpreterPython::AcquireInterpreterLock () +{ + std::unique_ptr<ScriptInterpreterLocker> py_lock(new Locker(this, + Locker::AcquireLock | Locker::InitSession, + Locker::FreeLock | Locker::TearDownSession)); + return py_lock; +} + +void +ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback python_swig_init_callback) +{ + g_swig_init_callback = python_swig_init_callback; + g_swig_breakpoint_callback = LLDBSwigPythonBreakpointCallbackFunction; + g_swig_watchpoint_callback = LLDBSwigPythonWatchpointCallbackFunction; + g_swig_typescript_callback = LLDBSwigPythonCallTypeScript; + g_swig_synthetic_script = LLDBSwigPythonCreateSyntheticProvider; + g_swig_calc_children = LLDBSwigPython_CalculateNumChildren; + g_swig_get_child_index = LLDBSwigPython_GetChildAtIndex; + g_swig_get_index_child = LLDBSwigPython_GetIndexOfChildWithName; + g_swig_cast_to_sbvalue = LLDBSWIGPython_CastPyObjectToSBValue; + g_swig_update_provider = LLDBSwigPython_UpdateSynthProviderInstance; + g_swig_mighthavechildren_provider = LLDBSwigPython_MightHaveChildrenSynthProviderInstance; + g_swig_call_command = LLDBSwigPythonCallCommand; + g_swig_call_module_init = LLDBSwigPythonCallModuleInit; + g_swig_create_os_plugin = LLDBSWIGPythonCreateOSPlugin; + g_swig_run_script_keyword_process = LLDBSWIGPythonRunScriptKeywordProcess; + g_swig_run_script_keyword_thread = LLDBSWIGPythonRunScriptKeywordThread; + g_swig_run_script_keyword_target = LLDBSWIGPythonRunScriptKeywordTarget; + g_swig_run_script_keyword_frame = LLDBSWIGPythonRunScriptKeywordFrame; +} + +void +ScriptInterpreterPython::InitializePrivate () +{ + Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); + + // Python will muck with STDIN terminal state, so save off any current TTY + // settings so we can restore them. + TerminalState stdin_tty_state; + stdin_tty_state.Save(STDIN_FILENO, false); + + PyGILState_STATE gstate; + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE)); + bool threads_already_initialized = false; + if (PyEval_ThreadsInitialized ()) { + gstate = PyGILState_Ensure (); + if (log) + log->Printf("Ensured PyGILState. Previous state = %slocked\n", gstate == PyGILState_UNLOCKED ? "un" : ""); + threads_already_initialized = true; + } else { + // InitThreads acquires the GIL if it hasn't been called before. + PyEval_InitThreads (); + } + Py_InitializeEx (0); + + // Initialize SWIG after setting up python + assert (g_swig_init_callback != NULL); + g_swig_init_callback (); + + // Update the path python uses to search for modules to include the current directory. + + PyRun_SimpleString ("import sys"); + PyRun_SimpleString ("sys.path.append ('.')"); + + // Find the module that owns this code and use that path we get to + // set the sys.path appropriately. + + FileSpec file_spec; + char python_dir_path[PATH_MAX]; + if (Host::GetLLDBPath (ePathTypePythonDir, file_spec)) + { + std::string python_path("sys.path.insert(0,\""); + size_t orig_len = python_path.length(); + if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path))) + { + python_path.append (python_dir_path); + python_path.append ("\")"); + PyRun_SimpleString (python_path.c_str()); + python_path.resize (orig_len); + } + + if (Host::GetLLDBPath (ePathTypeLLDBShlibDir, file_spec)) + { + if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path))) + { + python_path.append (python_dir_path); + python_path.append ("\")"); + PyRun_SimpleString (python_path.c_str()); + python_path.resize (orig_len); + } + } + } + + PyRun_SimpleString ("sys.dont_write_bytecode = 1; import lldb.embedded_interpreter; from lldb.embedded_interpreter import run_python_interpreter; from lldb.embedded_interpreter import run_one_line; from termios import *"); + + if (threads_already_initialized) { + if (log) + log->Printf("Releasing PyGILState. Returning to state = %slocked\n", gstate == PyGILState_UNLOCKED ? "un" : ""); + PyGILState_Release (gstate); + } else { + // We initialized the threads in this function, just unlock the GIL. + PyEval_SaveThread(); + } + + stdin_tty_state.Restore(); +} + +//void +//ScriptInterpreterPython::Terminate () +//{ +// // We are intentionally NOT calling Py_Finalize here (this would be the logical place to call it). Calling +// // Py_Finalize here causes test suite runs to seg fault: The test suite runs in Python. It registers +// // SBDebugger::Terminate to be called 'at_exit'. When the test suite Python harness finishes up, it calls +// // Py_Finalize, which calls all the 'at_exit' registered functions. SBDebugger::Terminate calls Debugger::Terminate, +// // which calls lldb::Terminate, which calls ScriptInterpreter::Terminate, which calls +// // ScriptInterpreterPython::Terminate. So if we call Py_Finalize here, we end up with Py_Finalize being called from +// // within Py_Finalize, which results in a seg fault. +// // +// // Since this function only gets called when lldb is shutting down and going away anyway, the fact that we don't +// // actually call Py_Finalize should not cause any problems (everything should shut down/go away anyway when the +// // process exits). +// // +//// Py_Finalize (); +//} + +#endif // #ifdef LLDB_DISABLE_PYTHON diff --git a/contrib/llvm/tools/lldb/source/Interpreter/embedded_interpreter.py b/contrib/llvm/tools/lldb/source/Interpreter/embedded_interpreter.py new file mode 100644 index 0000000..0e57c1e --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Interpreter/embedded_interpreter.py @@ -0,0 +1,103 @@ +import readline +import code +import sys +import traceback + +class SimpleREPL(code.InteractiveConsole): + def __init__(self, prompt, dict): + code.InteractiveConsole.__init__(self,dict) + self.prompt = prompt + self.loop_exit = False + self.dict = dict + + def interact(self): + try: + sys.ps1 + except AttributeError: + sys.ps1 = ">>> " + try: + sys.ps2 + except AttributeError: + sys.ps2 = "... " + + while not self.loop_exit: + try: + self.read_py_command() + except (SystemExit, EOFError): + # EOF while in Python just breaks out to top level. + self.write('\n') + self.loop_exit = True + break + except KeyboardInterrupt: + self.write("\nKeyboardInterrupt\n") + self.resetbuffer() + more = 0 + except: + traceback.print_exc() + + def process_input (self, in_str): + # Canonicalize the format of the input string + temp_str = in_str + temp_str.strip(' \t') + words = temp_str.split() + temp_str = ('').join(words) + + # Check the input string to see if it was the quit + # command. If so, intercept it, so that it doesn't + # close stdin on us! + if (temp_str.lower() == "quit()" or temp_str.lower() == "exit()"): + self.loop_exit = True + in_str = "raise SystemExit " + return in_str + + def my_raw_input (self, prompt): + stream = sys.stdout + stream.write (prompt) + stream.flush () + try: + line = sys.stdin.readline() + except KeyboardInterrupt: + line = " \n" + except (SystemExit, EOFError): + line = "quit()\n" + if not line: + raise EOFError + if line[-1] == '\n': + line = line[:-1] + return line + + def read_py_command(self): + # Read off a complete Python command. + more = 0 + while 1: + if more: + prompt = sys.ps2 + else: + prompt = sys.ps1 + line = self.my_raw_input(prompt) + # Can be None if sys.stdin was redefined + encoding = getattr(sys.stdin, "encoding", None) + if encoding and not isinstance(line, unicode): + line = line.decode(encoding) + line = self.process_input (line) + more = self.push(line) + if not more: + break + + def one_line (self, input): + line = self.process_input (input) + more = self.push(line) + if more: + self.write ("Input not a complete line.") + self.resetbuffer() + more = 0 + +def run_python_interpreter (dict): + # Pass in the dictionary, for continuity from one session to the next. + repl = SimpleREPL('>>> ', dict) + repl.interact() + +def run_one_line (dict, input_string): + repl = SimpleREPL ('', dict) + repl.one_line (input_string) + |