summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/lldb/source/Commands
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Commands')
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandCompletions.cpp754
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectApropos.cpp154
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectApropos.h44
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.cpp272
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.h72
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpoint.cpp1843
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpoint.h47
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp915
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.h46
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp2021
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.h40
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.cpp574
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.h110
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.cpp505
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.h99
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.cpp624
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.h40
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectHelp.cpp249
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectHelp.h119
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectLog.cpp503
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectLog.h48
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectMemory.cpp1370
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectMemory.h33
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectMultiword.cpp520
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectPlatform.cpp987
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectPlatform.h40
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectPlugin.cpp122
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectPlugin.h36
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.cpp1945
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.h37
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectQuit.cpp99
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectQuit.h46
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp499
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.h45
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectSettings.cpp1208
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectSettings.h41
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.cpp925
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.h40
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectSyntax.cpp113
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectSyntax.h44
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.cpp5354
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.h41
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectThread.cpp1526
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectThread.h34
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectType.cpp4112
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectType.h37
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectVersion.cpp53
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectVersion.h43
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpoint.cpp1394
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpoint.h43
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.cpp850
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.h46
52 files changed, 30762 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandCompletions.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandCompletions.cpp
new file mode 100644
index 0000000..a9d2f21
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandCompletions.cpp
@@ -0,0 +1,754 @@
+//===-- CommandCompletions.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 <sys/stat.h>
+#include <dirent.h>
+#if defined(__APPLE__) || defined(__linux__)
+#include <pwd.h>
+#endif
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/CleanUp.h"
+
+using namespace lldb_private;
+
+CommandCompletions::CommonCompletionElement
+CommandCompletions::g_common_completions[] =
+{
+ {eCustomCompletion, NULL},
+ {eSourceFileCompletion, CommandCompletions::SourceFiles},
+ {eDiskFileCompletion, CommandCompletions::DiskFiles},
+ {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
+ {eSymbolCompletion, CommandCompletions::Symbols},
+ {eModuleCompletion, CommandCompletions::Modules},
+ {eSettingsNameCompletion, CommandCompletions::SettingsNames},
+ {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames},
+ {eArchitectureCompletion, CommandCompletions::ArchitectureNames},
+ {eVariablePathCompletion, CommandCompletions::VariablePath},
+ {eNoCompletion, NULL} // This one has to be last in the list.
+};
+
+bool
+CommandCompletions::InvokeCommonCompletionCallbacks
+(
+ CommandInterpreter &interpreter,
+ uint32_t completion_mask,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches
+)
+{
+ bool handled = false;
+
+ if (completion_mask & eCustomCompletion)
+ return false;
+
+ for (int i = 0; ; i++)
+ {
+ if (g_common_completions[i].type == eNoCompletion)
+ break;
+ else if ((g_common_completions[i].type & completion_mask) == g_common_completions[i].type
+ && g_common_completions[i].callback != NULL)
+ {
+ handled = true;
+ g_common_completions[i].callback (interpreter,
+ completion_str,
+ match_start_point,
+ max_return_elements,
+ searcher,
+ word_complete,
+ matches);
+ }
+ }
+ return handled;
+}
+
+int
+CommandCompletions::SourceFiles
+(
+ CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches
+)
+{
+ word_complete = true;
+ // Find some way to switch "include support files..."
+ SourceFileCompleter completer (interpreter,
+ false,
+ partial_file_name,
+ match_start_point,
+ max_return_elements,
+ matches);
+
+ if (searcher == NULL)
+ {
+ lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
+ SearchFilter null_searcher (target_sp);
+ completer.DoCompletion (&null_searcher);
+ }
+ else
+ {
+ completer.DoCompletion (searcher);
+ }
+ return matches.GetSize();
+}
+
+static int
+DiskFilesOrDirectories
+(
+ const char *partial_file_name,
+ bool only_directories,
+ bool &saw_directory,
+ StringList &matches
+)
+{
+ // I'm going to use the "glob" function with GLOB_TILDE for user directory expansion.
+ // If it is not defined on your host system, you'll need to implement it yourself...
+
+ size_t partial_name_len = strlen(partial_file_name);
+
+ if (partial_name_len >= PATH_MAX)
+ return matches.GetSize();
+
+ // This copy of the string will be cut up into the directory part, and the remainder. end_ptr
+ // below will point to the place of the remainder in this string. Then when we've resolved the
+ // containing directory, and opened it, we'll read the directory contents and overwrite the
+ // partial_name_copy starting from end_ptr with each of the matches. Thus we will preserve
+ // the form the user originally typed.
+
+ char partial_name_copy[PATH_MAX];
+ memcpy(partial_name_copy, partial_file_name, partial_name_len);
+ partial_name_copy[partial_name_len] = '\0';
+
+ // We'll need to save a copy of the remainder for comparison, which we do here.
+ char remainder[PATH_MAX];
+
+ // end_ptr will point past the last / in partial_name_copy, or if there is no slash to the beginning of the string.
+ char *end_ptr;
+
+ end_ptr = strrchr(partial_name_copy, '/');
+
+ // This will store the resolved form of the containing directory
+ char containing_part[PATH_MAX];
+
+ if (end_ptr == NULL)
+ {
+ // There's no directory. If the thing begins with a "~" then this is a bare
+ // user name.
+ if (*partial_name_copy == '~')
+ {
+ // Nothing here but the user name. We could just put a slash on the end,
+ // but for completeness sake we'll resolve the user name and only put a slash
+ // on the end if it exists.
+ char resolved_username[PATH_MAX];
+ size_t resolved_username_len = FileSpec::ResolveUsername (partial_name_copy, resolved_username,
+ sizeof (resolved_username));
+
+ // Not sure how this would happen, a username longer than PATH_MAX? Still...
+ if (resolved_username_len >= sizeof (resolved_username))
+ return matches.GetSize();
+ else if (resolved_username_len == 0)
+ {
+ // The user name didn't resolve, let's look in the password database for matches.
+ // The user name database contains duplicates, and is not in alphabetical order, so
+ // we'll use a set to manage that for us.
+ FileSpec::ResolvePartialUsername (partial_name_copy, matches);
+ if (matches.GetSize() > 0)
+ saw_directory = true;
+ return matches.GetSize();
+ }
+ else
+ {
+ //The thing exists, put a '/' on the end, and return it...
+ // FIXME: complete user names here:
+ partial_name_copy[partial_name_len] = '/';
+ partial_name_copy[partial_name_len+1] = '\0';
+ matches.AppendString(partial_name_copy);
+ saw_directory = true;
+ return matches.GetSize();
+ }
+ }
+ else
+ {
+ // The containing part is the CWD, and the whole string is the remainder.
+ containing_part[0] = '.';
+ containing_part[1] = '\0';
+ strcpy(remainder, partial_name_copy);
+ end_ptr = partial_name_copy;
+ }
+ }
+ else
+ {
+ if (end_ptr == partial_name_copy)
+ {
+ // We're completing a file or directory in the root volume.
+ containing_part[0] = '/';
+ containing_part[1] = '\0';
+ }
+ else
+ {
+ size_t len = end_ptr - partial_name_copy;
+ memcpy(containing_part, partial_name_copy, len);
+ containing_part[len] = '\0';
+ }
+ // Push end_ptr past the final "/" and set remainder.
+ end_ptr++;
+ strcpy(remainder, end_ptr);
+ }
+
+ // Look for a user name in the containing part, and if it's there, resolve it and stick the
+ // result back into the containing_part:
+
+ if (*partial_name_copy == '~')
+ {
+ size_t resolved_username_len = FileSpec::ResolveUsername(containing_part,
+ containing_part,
+ sizeof (containing_part));
+ // User name doesn't exist, we're not getting any further...
+ if (resolved_username_len == 0 || resolved_username_len >= sizeof (containing_part))
+ return matches.GetSize();
+ }
+
+ // Okay, containing_part is now the directory we want to open and look for files:
+
+ lldb_utility::CleanUp <DIR *, int> dir_stream (opendir(containing_part), NULL, closedir);
+ if (!dir_stream.is_valid())
+ return matches.GetSize();
+
+ struct dirent *dirent_buf;
+
+ size_t baselen = end_ptr - partial_name_copy;
+
+ while ((dirent_buf = readdir(dir_stream.get())) != NULL)
+ {
+ char *name = dirent_buf->d_name;
+
+ // Omit ".", ".." and any . files if the match string doesn't start with .
+ if (name[0] == '.')
+ {
+ if (name[1] == '\0')
+ continue;
+ else if (name[1] == '.' && name[2] == '\0')
+ continue;
+ else if (remainder[0] != '.')
+ continue;
+ }
+
+ // If we found a directory, we put a "/" at the end of the name.
+
+ if (remainder[0] == '\0' || strstr(dirent_buf->d_name, remainder) == name)
+ {
+ if (strlen(name) + baselen >= PATH_MAX)
+ continue;
+
+ strcpy(end_ptr, name);
+
+ bool isa_directory = false;
+ if (dirent_buf->d_type & DT_DIR)
+ isa_directory = true;
+ else if (dirent_buf->d_type & DT_LNK)
+ {
+ struct stat stat_buf;
+ if ((stat(partial_name_copy, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode))
+ isa_directory = true;
+ }
+
+ if (isa_directory)
+ {
+ saw_directory = true;
+ size_t len = strlen(partial_name_copy);
+ partial_name_copy[len] = '/';
+ partial_name_copy[len + 1] = '\0';
+ }
+ if (only_directories && !isa_directory)
+ continue;
+ matches.AppendString(partial_name_copy);
+ }
+ }
+
+ return matches.GetSize();
+}
+
+int
+CommandCompletions::DiskFiles
+(
+ CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches
+)
+{
+
+ int ret_val = DiskFilesOrDirectories (partial_file_name,
+ false,
+ word_complete,
+ matches);
+ word_complete = !word_complete;
+ return ret_val;
+}
+
+int
+CommandCompletions::DiskDirectories
+(
+ CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches
+)
+{
+ int ret_val = DiskFilesOrDirectories (partial_file_name,
+ true,
+ word_complete,
+ matches);
+ word_complete = false;
+ return ret_val;
+}
+
+int
+CommandCompletions::Modules
+(
+ CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches
+)
+{
+ word_complete = true;
+ ModuleCompleter completer (interpreter,
+ partial_file_name,
+ match_start_point,
+ max_return_elements,
+ matches);
+
+ if (searcher == NULL)
+ {
+ lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
+ SearchFilter null_searcher (target_sp);
+ completer.DoCompletion (&null_searcher);
+ }
+ else
+ {
+ completer.DoCompletion (searcher);
+ }
+ return matches.GetSize();
+}
+
+int
+CommandCompletions::Symbols
+(
+ CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches)
+{
+ word_complete = true;
+ SymbolCompleter completer (interpreter,
+ partial_file_name,
+ match_start_point,
+ max_return_elements,
+ matches);
+
+ if (searcher == NULL)
+ {
+ lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
+ SearchFilter null_searcher (target_sp);
+ completer.DoCompletion (&null_searcher);
+ }
+ else
+ {
+ completer.DoCompletion (searcher);
+ }
+ return matches.GetSize();
+}
+
+int
+CommandCompletions::SettingsNames (CommandInterpreter &interpreter,
+ const char *partial_setting_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches)
+{
+ // Cache the full setting name list
+ static StringList g_property_names;
+ if (g_property_names.GetSize() == 0)
+ {
+ // Generate the full setting name list on demand
+ lldb::OptionValuePropertiesSP properties_sp (interpreter.GetDebugger().GetValueProperties());
+ if (properties_sp)
+ {
+ StreamString strm;
+ properties_sp->DumpValue(NULL, strm, OptionValue::eDumpOptionName);
+ const std::string &str = strm.GetString();
+ g_property_names.SplitIntoLines(str.c_str(), str.size());
+ }
+ }
+
+ size_t exact_matches_idx = SIZE_MAX;
+ const size_t num_matches = g_property_names.AutoComplete (partial_setting_name, matches, exact_matches_idx);
+ word_complete = exact_matches_idx != SIZE_MAX;
+ return num_matches;
+}
+
+
+int
+CommandCompletions::PlatformPluginNames (CommandInterpreter &interpreter,
+ const char *partial_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ lldb_private::StringList &matches)
+{
+ const uint32_t num_matches = PluginManager::AutoCompletePlatformName(partial_name, matches);
+ word_complete = num_matches == 1;
+ return num_matches;
+}
+
+int
+CommandCompletions::ArchitectureNames (CommandInterpreter &interpreter,
+ const char *partial_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ lldb_private::StringList &matches)
+{
+ const uint32_t num_matches = ArchSpec::AutoComplete (partial_name, matches);
+ word_complete = num_matches == 1;
+ return num_matches;
+}
+
+
+int
+CommandCompletions::VariablePath (CommandInterpreter &interpreter,
+ const char *partial_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ lldb_private::StringList &matches)
+{
+ return Variable::AutoComplete (interpreter.GetExecutionContext(), partial_name, matches, word_complete);
+}
+
+
+CommandCompletions::Completer::Completer
+(
+ CommandInterpreter &interpreter,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches
+) :
+ m_interpreter (interpreter),
+ m_completion_str (completion_str),
+ m_match_start_point (match_start_point),
+ m_max_return_elements (max_return_elements),
+ m_matches (matches)
+{
+}
+
+CommandCompletions::Completer::~Completer ()
+{
+
+}
+
+//----------------------------------------------------------------------
+// SourceFileCompleter
+//----------------------------------------------------------------------
+
+CommandCompletions::SourceFileCompleter::SourceFileCompleter
+(
+ CommandInterpreter &interpreter,
+ bool include_support_files,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches
+) :
+ CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches),
+ m_include_support_files (include_support_files),
+ m_matching_files()
+{
+ FileSpec partial_spec (m_completion_str.c_str(), false);
+ m_file_name = partial_spec.GetFilename().GetCString();
+ m_dir_name = partial_spec.GetDirectory().GetCString();
+}
+
+Searcher::Depth
+CommandCompletions::SourceFileCompleter::GetDepth()
+{
+ return eDepthCompUnit;
+}
+
+Searcher::CallbackReturn
+CommandCompletions::SourceFileCompleter::SearchCallback (
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool complete
+)
+{
+ if (context.comp_unit != NULL)
+ {
+ if (m_include_support_files)
+ {
+ FileSpecList supporting_files = context.comp_unit->GetSupportFiles();
+ for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++)
+ {
+ const FileSpec &sfile_spec = supporting_files.GetFileSpecAtIndex(sfiles);
+ const char *sfile_file_name = sfile_spec.GetFilename().GetCString();
+ const char *sfile_dir_name = sfile_spec.GetFilename().GetCString();
+ bool match = false;
+ if (m_file_name && sfile_file_name
+ && strstr (sfile_file_name, m_file_name) == sfile_file_name)
+ match = true;
+ if (match && m_dir_name && sfile_dir_name
+ && strstr (sfile_dir_name, m_dir_name) != sfile_dir_name)
+ match = false;
+
+ if (match)
+ {
+ m_matching_files.AppendIfUnique(sfile_spec);
+ }
+ }
+
+ }
+ else
+ {
+ const char *cur_file_name = context.comp_unit->GetFilename().GetCString();
+ const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString();
+
+ bool match = false;
+ if (m_file_name && cur_file_name
+ && strstr (cur_file_name, m_file_name) == cur_file_name)
+ match = true;
+
+ if (match && m_dir_name && cur_dir_name
+ && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
+ match = false;
+
+ if (match)
+ {
+ m_matching_files.AppendIfUnique(context.comp_unit);
+ }
+ }
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+size_t
+CommandCompletions::SourceFileCompleter::DoCompletion (SearchFilter *filter)
+{
+ filter->Search (*this);
+ // Now convert the filelist to completions:
+ for (size_t i = 0; i < m_matching_files.GetSize(); i++)
+ {
+ m_matches.AppendString (m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
+ }
+ return m_matches.GetSize();
+
+}
+
+//----------------------------------------------------------------------
+// SymbolCompleter
+//----------------------------------------------------------------------
+
+static bool
+regex_chars (const char comp)
+{
+ if (comp == '[' || comp == ']' ||
+ comp == '(' || comp == ')' ||
+ comp == '{' || comp == '}' ||
+ comp == '+' ||
+ comp == '.' ||
+ comp == '*' ||
+ comp == '|' ||
+ comp == '^' ||
+ comp == '$' ||
+ comp == '\\' ||
+ comp == '?')
+ return true;
+ else
+ return false;
+}
+CommandCompletions::SymbolCompleter::SymbolCompleter
+(
+ CommandInterpreter &interpreter,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches
+) :
+ CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
+{
+ std::string regex_str;
+ if (completion_str && completion_str[0])
+ {
+ regex_str.append("^");
+ regex_str.append(completion_str);
+ }
+ else
+ {
+ // Match anything since the completion string is empty
+ regex_str.append(".");
+ }
+ std::string::iterator pos = find_if(regex_str.begin() + 1, regex_str.end(), regex_chars);
+ while (pos < regex_str.end())
+ {
+ pos = regex_str.insert(pos, '\\');
+ pos = find_if(pos + 2, regex_str.end(), regex_chars);
+ }
+ m_regex.Compile(regex_str.c_str());
+}
+
+Searcher::Depth
+CommandCompletions::SymbolCompleter::GetDepth()
+{
+ return eDepthModule;
+}
+
+Searcher::CallbackReturn
+CommandCompletions::SymbolCompleter::SearchCallback (
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool complete
+)
+{
+ if (context.module_sp)
+ {
+ SymbolContextList sc_list;
+ const bool include_symbols = true;
+ const bool include_inlines = true;
+ const bool append = true;
+ context.module_sp->FindFunctions (m_regex, include_symbols, include_inlines, append, sc_list);
+
+ SymbolContext sc;
+ // Now add the functions & symbols to the list - only add if unique:
+ for (uint32_t i = 0; i < sc_list.GetSize(); i++)
+ {
+ if (sc_list.GetContextAtIndex(i, sc))
+ {
+ ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled);
+ if (!func_name.IsEmpty())
+ m_match_set.insert (func_name);
+ }
+ }
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+size_t
+CommandCompletions::SymbolCompleter::DoCompletion (SearchFilter *filter)
+{
+ filter->Search (*this);
+ collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
+ for (pos = m_match_set.begin(); pos != end; pos++)
+ m_matches.AppendString((*pos).GetCString());
+
+ return m_matches.GetSize();
+}
+
+//----------------------------------------------------------------------
+// ModuleCompleter
+//----------------------------------------------------------------------
+CommandCompletions::ModuleCompleter::ModuleCompleter
+(
+ CommandInterpreter &interpreter,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches
+) :
+ CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
+{
+ FileSpec partial_spec (m_completion_str.c_str(), false);
+ m_file_name = partial_spec.GetFilename().GetCString();
+ m_dir_name = partial_spec.GetDirectory().GetCString();
+}
+
+Searcher::Depth
+CommandCompletions::ModuleCompleter::GetDepth()
+{
+ return eDepthModule;
+}
+
+Searcher::CallbackReturn
+CommandCompletions::ModuleCompleter::SearchCallback (
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool complete
+)
+{
+ if (context.module_sp)
+ {
+ const char *cur_file_name = context.module_sp->GetFileSpec().GetFilename().GetCString();
+ const char *cur_dir_name = context.module_sp->GetFileSpec().GetDirectory().GetCString();
+
+ bool match = false;
+ if (m_file_name && cur_file_name
+ && strstr (cur_file_name, m_file_name) == cur_file_name)
+ match = true;
+
+ if (match && m_dir_name && cur_dir_name
+ && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
+ match = false;
+
+ if (match)
+ {
+ m_matches.AppendString (cur_file_name);
+ }
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+size_t
+CommandCompletions::ModuleCompleter::DoCompletion (SearchFilter *filter)
+{
+ filter->Search (*this);
+ return m_matches.GetSize();
+}
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectApropos.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectApropos.cpp
new file mode 100644
index 0000000..02dc726
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectApropos.cpp
@@ -0,0 +1,154 @@
+//===-- CommandObjectApropos.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 "CommandObjectApropos.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/Options.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectApropos
+//-------------------------------------------------------------------------
+
+CommandObjectApropos::CommandObjectApropos (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "apropos",
+ "Find a list of debugger commands related to a particular word/subject.",
+ NULL)
+{
+ CommandArgumentEntry arg;
+ CommandArgumentData search_word_arg;
+
+ // Define the first (and only) variant of this arg.
+ search_word_arg.arg_type = eArgTypeSearchWord;
+ search_word_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (search_word_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+}
+
+CommandObjectApropos::~CommandObjectApropos()
+{
+}
+
+
+bool
+CommandObjectApropos::DoExecute (Args& args, CommandReturnObject &result)
+{
+ const size_t argc = args.GetArgumentCount ();
+
+ if (argc == 1)
+ {
+ const char *search_word = args.GetArgumentAtIndex(0);
+ if ((search_word != NULL)
+ && (strlen (search_word) > 0))
+ {
+ // The bulk of the work must be done inside the Command Interpreter, since the command dictionary
+ // is private.
+ StringList commands_found;
+ StringList commands_help;
+ StringList user_commands_found;
+ StringList user_commands_help;
+
+ m_interpreter.FindCommandsForApropos (search_word, commands_found, commands_help, true, false);
+ m_interpreter.FindCommandsForApropos (search_word, user_commands_found, user_commands_help, false, true);
+
+ if (commands_found.GetSize() == 0 && user_commands_found.GetSize() == 0)
+ {
+ result.AppendMessageWithFormat ("No commands found pertaining to '%s'. Try 'help' to see a complete list of debugger commands.\n", search_word);
+ }
+ else
+ {
+ if (commands_found.GetSize() > 0)
+ {
+ result.AppendMessageWithFormat ("The following built-in commands may relate to '%s':\n", search_word);
+ size_t max_len = 0;
+
+ for (size_t i = 0; i < commands_found.GetSize(); ++i)
+ {
+ size_t len = strlen (commands_found.GetStringAtIndex (i));
+ if (len > max_len)
+ max_len = len;
+ }
+
+ for (size_t i = 0; i < commands_found.GetSize(); ++i)
+ m_interpreter.OutputFormattedHelpText (result.GetOutputStream(),
+ commands_found.GetStringAtIndex(i),
+ "--",
+ commands_help.GetStringAtIndex(i),
+ max_len);
+ if (user_commands_found.GetSize() > 0)
+ result.AppendMessage("");
+ }
+
+ if (user_commands_found.GetSize() > 0)
+ {
+ result.AppendMessageWithFormat ("The following user commands may relate to '%s':\n", search_word);
+ size_t max_len = 0;
+
+ for (size_t i = 0; i < user_commands_found.GetSize(); ++i)
+ {
+ size_t len = strlen (user_commands_found.GetStringAtIndex (i));
+ if (len > max_len)
+ max_len = len;
+ }
+
+ for (size_t i = 0; i < user_commands_found.GetSize(); ++i)
+ m_interpreter.OutputFormattedHelpText (result.GetOutputStream(),
+ user_commands_found.GetStringAtIndex(i),
+ "--",
+ user_commands_help.GetStringAtIndex(i),
+ max_len);
+ }
+
+ }
+
+
+ std::vector<const Property *> properties;
+ const size_t num_properties = m_interpreter.GetDebugger().Apropos(search_word, properties);
+ if (num_properties)
+ {
+ const bool dump_qualified_name = true;
+ result.AppendMessageWithFormat ("\nThe following settings variables may relate to '%s': \n\n", search_word);
+ for (size_t i=0; i<num_properties; ++i)
+ properties[i]->DumpDescription (m_interpreter, result.GetOutputStream(), 0, dump_qualified_name);
+
+ }
+
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("'' is not a valid search word.\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("'apropos' must be called with exactly one argument.\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+}
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectApropos.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectApropos.h
new file mode 100644
index 0000000..f515417
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectApropos.h
@@ -0,0 +1,44 @@
+//===-- CommandObjectApropos.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_CommandObjectApropos_h_
+#define liblldb_CommandObjectApropos_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectApropos
+//-------------------------------------------------------------------------
+
+class CommandObjectApropos : public CommandObjectParsed
+{
+public:
+
+ CommandObjectApropos (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectApropos ();
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result);
+
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectApropos_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.cpp
new file mode 100644
index 0000000..05fd53b
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.cpp
@@ -0,0 +1,272 @@
+//===-- CommandObjectArgs.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 "CommandObjectArgs.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/StackFrame.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// This command is a toy. I'm just using it to have a way to construct the arguments to
+// calling functions.
+//
+
+CommandObjectArgs::CommandOptions::CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+{
+ // Keep only one place to reset the values to their defaults
+ OptionParsingStarting();
+}
+
+
+CommandObjectArgs::CommandOptions::~CommandOptions ()
+{
+}
+
+Error
+CommandObjectArgs::CommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg)
+{
+ Error error;
+
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectArgs::CommandOptions::OptionParsingStarting ()
+{
+}
+
+const OptionDefinition*
+CommandObjectArgs::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+CommandObjectArgs::CommandObjectArgs (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "args",
+ "When stopped at the start of a function, reads function arguments of type (u?)int(8|16|32|64)_t, (void|char)*",
+ "args"),
+ m_options (interpreter)
+{
+}
+
+CommandObjectArgs::~CommandObjectArgs ()
+{
+}
+
+Options *
+CommandObjectArgs::GetOptions ()
+{
+ return &m_options;
+}
+
+bool
+CommandObjectArgs::DoExecute (Args& args, CommandReturnObject &result)
+{
+ ConstString target_triple;
+
+
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (!process)
+ {
+ result.AppendError ("Args found no process.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const ABI *abi = process->GetABI().get();
+ if (!abi)
+ {
+ result.AppendError ("The current process has no ABI.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const size_t num_args = args.GetArgumentCount ();
+ size_t arg_index;
+
+ if (!num_args)
+ {
+ result.AppendError ("args requires at least one argument");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+
+ if (!thread)
+ {
+ result.AppendError ("args found no thread.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ lldb::StackFrameSP thread_cur_frame = thread->GetSelectedFrame ();
+ if (!thread_cur_frame)
+ {
+ result.AppendError ("The current thread has no current frame.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ModuleSP thread_module_sp (thread_cur_frame->GetFrameCodeAddress ().GetModule());
+ if (!thread_module_sp)
+ {
+ result.AppendError ("The PC has no associated module.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ClangASTContext &ast_context = thread_module_sp->GetClangASTContext();
+
+ ValueList value_list;
+
+ for (arg_index = 0; arg_index < num_args; ++arg_index)
+ {
+ const char *arg_type_cstr = args.GetArgumentAtIndex(arg_index);
+ Value value;
+ value.SetValueType(Value::eValueTypeScalar);
+ ClangASTType clang_type;
+
+ char *int_pos;
+ if ((int_pos = strstr (const_cast<char*>(arg_type_cstr), "int")))
+ {
+ Encoding encoding = eEncodingSint;
+
+ int width = 0;
+
+ if (int_pos > arg_type_cstr + 1)
+ {
+ result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ if (int_pos == arg_type_cstr + 1 && arg_type_cstr[0] != 'u')
+ {
+ result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ if (arg_type_cstr[0] == 'u')
+ {
+ encoding = eEncodingUint;
+ }
+
+ char *width_pos = int_pos + 3;
+
+ if (!strcmp (width_pos, "8_t"))
+ width = 8;
+ else if (!strcmp (width_pos, "16_t"))
+ width = 16;
+ else if (!strcmp (width_pos, "32_t"))
+ width = 32;
+ else if (!strcmp (width_pos, "64_t"))
+ width = 64;
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ clang_type = ast_context.GetBuiltinTypeForEncodingAndBitSize(encoding, width);
+
+ if (!clang_type.IsValid())
+ {
+ result.AppendErrorWithFormat ("Couldn't get Clang type for format %s (%s integer, width %d).\n",
+ arg_type_cstr,
+ (encoding == eEncodingSint ? "signed" : "unsigned"),
+ width);
+
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else if (strchr (arg_type_cstr, '*'))
+ {
+ if (!strcmp (arg_type_cstr, "void*"))
+ clang_type = ast_context.GetBasicType(eBasicTypeVoid).GetPointerType();
+ else if (!strcmp (arg_type_cstr, "char*"))
+ clang_type = ast_context.GetCStringType (false);
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ value.SetClangType (clang_type);
+ value_list.PushValue(value);
+ }
+
+ if (!abi->GetArgumentValues (*thread, value_list))
+ {
+ result.AppendError ("Couldn't get argument values");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ result.GetOutputStream ().Printf("Arguments : \n");
+
+ for (arg_index = 0; arg_index < num_args; ++arg_index)
+ {
+ result.GetOutputStream ().Printf ("%zu (%s): ", arg_index, args.GetArgumentAtIndex (arg_index));
+ value_list.GetValueAtIndex (arg_index)->Dump (&result.GetOutputStream ());
+ result.GetOutputStream ().Printf("\n");
+ }
+
+ return result.Succeeded();
+}
+
+OptionDefinition
+CommandObjectArgs::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "debug", 'g', no_argument, NULL, 0, eArgTypeNone, "Enable verbose debug logging of the expression parsing and evaluation."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.h
new file mode 100644
index 0000000..6691283
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.h
@@ -0,0 +1,72 @@
+//===-- CommandObjectArgs.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_CommandObjectArgs_h_
+#define liblldb_CommandObjectArgs_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/Language.h"
+
+namespace lldb_private {
+
+ class CommandObjectArgs : public CommandObjectParsed
+ {
+ public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandOptions ();
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg);
+
+ void
+ OptionParsingStarting ();
+
+ const OptionDefinition*
+ GetDefinitions ();
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+ };
+
+ CommandObjectArgs (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectArgs ();
+
+ virtual
+ Options *
+ GetOptions ();
+
+
+ protected:
+
+ CommandOptions m_options;
+
+ virtual bool
+ DoExecute ( Args& command,
+ CommandReturnObject &result);
+
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectArgs_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpoint.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpoint.cpp
new file mode 100644
index 0000000..cb70c99
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpoint.cpp
@@ -0,0 +1,1843 @@
+//===-- CommandObjectBreakpoint.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 "CommandObjectBreakpoint.h"
+#include "CommandObjectBreakpointCommand.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointIDList.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static void
+AddBreakpointDescription (Stream *s, Breakpoint *bp, lldb::DescriptionLevel level)
+{
+ s->IndentMore();
+ bp->GetDescription (s, level, true);
+ s->IndentLess();
+ s->EOL();
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointSet
+//-------------------------------------------------------------------------
+
+
+class CommandObjectBreakpointSet : public CommandObjectParsed
+{
+public:
+
+ typedef enum BreakpointSetType
+ {
+ eSetTypeInvalid,
+ eSetTypeFileAndLine,
+ eSetTypeAddress,
+ eSetTypeFunctionName,
+ eSetTypeFunctionRegexp,
+ eSetTypeSourceRegexp,
+ eSetTypeException
+ } BreakpointSetType;
+
+ CommandObjectBreakpointSet (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "breakpoint set",
+ "Sets a breakpoint or set of breakpoints in the executable.",
+ "breakpoint set <cmd-options>"),
+ m_options (interpreter)
+ {
+ }
+
+
+ virtual
+ ~CommandObjectBreakpointSet () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_condition (),
+ m_filenames (),
+ m_line_num (0),
+ m_column (0),
+ m_func_names (),
+ m_func_name_type_mask (eFunctionNameTypeNone),
+ m_func_regexp (),
+ m_source_text_regexp(),
+ m_modules (),
+ m_load_addr(),
+ m_ignore_count (0),
+ m_thread_id(LLDB_INVALID_THREAD_ID),
+ m_thread_index (UINT32_MAX),
+ m_thread_name(),
+ m_queue_name(),
+ m_catch_bp (false),
+ m_throw_bp (true),
+ m_language (eLanguageTypeUnknown),
+ m_skip_prologue (eLazyBoolCalculate),
+ m_one_shot (false)
+ {
+ }
+
+
+ virtual
+ ~CommandOptions () {}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ {
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ m_load_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ }
+ break;
+
+ case 'b':
+ m_func_names.push_back (option_arg);
+ m_func_name_type_mask |= eFunctionNameTypeBase;
+ break;
+
+ case 'C':
+ m_column = Args::StringToUInt32 (option_arg, 0);
+ break;
+
+ case 'c':
+ m_condition.assign(option_arg);
+ break;
+
+ case 'E':
+ {
+ LanguageType language = LanguageRuntime::GetLanguageTypeFromString (option_arg);
+
+ switch (language)
+ {
+ case eLanguageTypeC89:
+ case eLanguageTypeC:
+ case eLanguageTypeC99:
+ m_language = eLanguageTypeC;
+ break;
+ case eLanguageTypeC_plus_plus:
+ m_language = eLanguageTypeC_plus_plus;
+ break;
+ case eLanguageTypeObjC:
+ m_language = eLanguageTypeObjC;
+ break;
+ case eLanguageTypeObjC_plus_plus:
+ error.SetErrorStringWithFormat ("Set exception breakpoints separately for c++ and objective-c");
+ break;
+ case eLanguageTypeUnknown:
+ error.SetErrorStringWithFormat ("Unknown language type: '%s' for exception breakpoint", option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("Unsupported language type: '%s' for exception breakpoint", option_arg);
+ }
+ }
+ break;
+
+ case 'f':
+ m_filenames.AppendIfUnique (FileSpec(option_arg, false));
+ break;
+
+ case 'F':
+ m_func_names.push_back (option_arg);
+ m_func_name_type_mask |= eFunctionNameTypeFull;
+ break;
+
+ case 'h':
+ {
+ bool success;
+ m_catch_bp = Args::StringToBoolean (option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("Invalid boolean value for on-catch option: '%s'", option_arg);
+ }
+ break;
+ case 'i':
+ {
+ m_ignore_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0);
+ if (m_ignore_count == UINT32_MAX)
+ error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg);
+ break;
+ }
+
+ case 'K':
+ {
+ bool success;
+ bool value;
+ value = Args::StringToBoolean (option_arg, true, &success);
+ if (value)
+ m_skip_prologue = eLazyBoolYes;
+ else
+ m_skip_prologue = eLazyBoolNo;
+
+ if (!success)
+ error.SetErrorStringWithFormat ("Invalid boolean value for skip prologue option: '%s'", option_arg);
+ }
+ break;
+
+ case 'l':
+ m_line_num = Args::StringToUInt32 (option_arg, 0);
+ break;
+
+ case 'M':
+ m_func_names.push_back (option_arg);
+ m_func_name_type_mask |= eFunctionNameTypeMethod;
+ break;
+
+ case 'n':
+ m_func_names.push_back (option_arg);
+ m_func_name_type_mask |= eFunctionNameTypeAuto;
+ break;
+
+ case 'o':
+ m_one_shot = true;
+ break;
+
+ case 'p':
+ m_source_text_regexp.assign (option_arg);
+ break;
+
+ case 'q':
+ m_queue_name.assign (option_arg);
+ break;
+
+ case 'r':
+ m_func_regexp.assign (option_arg);
+ break;
+
+ case 's':
+ {
+ m_modules.AppendIfUnique (FileSpec (option_arg, false));
+ break;
+ }
+
+ case 'S':
+ m_func_names.push_back (option_arg);
+ m_func_name_type_mask |= eFunctionNameTypeSelector;
+ break;
+
+ case 't' :
+ {
+ m_thread_id = Args::StringToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0);
+ if (m_thread_id == LLDB_INVALID_THREAD_ID)
+ error.SetErrorStringWithFormat ("invalid thread id string '%s'", option_arg);
+ }
+ break;
+
+ case 'T':
+ m_thread_name.assign (option_arg);
+ break;
+
+ case 'w':
+ {
+ bool success;
+ m_throw_bp = Args::StringToBoolean (option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("Invalid boolean value for on-throw option: '%s'", option_arg);
+ }
+ break;
+
+ case 'x':
+ {
+ m_thread_index = Args::StringToUInt32(option_arg, UINT32_MAX, 0);
+ if (m_thread_id == UINT32_MAX)
+ error.SetErrorStringWithFormat ("invalid thread index string '%s'", option_arg);
+
+ }
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+ void
+ OptionParsingStarting ()
+ {
+ m_condition.clear();
+ m_filenames.Clear();
+ m_line_num = 0;
+ m_column = 0;
+ m_func_names.clear();
+ m_func_name_type_mask = eFunctionNameTypeNone;
+ m_func_regexp.clear();
+ m_source_text_regexp.clear();
+ m_modules.Clear();
+ m_load_addr = LLDB_INVALID_ADDRESS;
+ m_ignore_count = 0;
+ m_thread_id = LLDB_INVALID_THREAD_ID;
+ m_thread_index = UINT32_MAX;
+ m_thread_name.clear();
+ m_queue_name.clear();
+ m_catch_bp = false;
+ m_throw_bp = true;
+ m_language = eLanguageTypeUnknown;
+ m_skip_prologue = eLazyBoolCalculate;
+ m_one_shot = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ std::string m_condition;
+ FileSpecList m_filenames;
+ uint32_t m_line_num;
+ uint32_t m_column;
+ std::vector<std::string> m_func_names;
+ uint32_t m_func_name_type_mask;
+ std::string m_func_regexp;
+ std::string m_source_text_regexp;
+ FileSpecList m_modules;
+ lldb::addr_t m_load_addr;
+ uint32_t m_ignore_count;
+ lldb::tid_t m_thread_id;
+ uint32_t m_thread_index;
+ std::string m_thread_name;
+ std::string m_queue_name;
+ bool m_catch_bp;
+ bool m_throw_bp;
+ lldb::LanguageType m_language;
+ LazyBool m_skip_prologue;
+ bool m_one_shot;
+
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. Must set target before setting breakpoints (see 'target create' command).");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // The following are the various types of breakpoints that could be set:
+ // 1). -f -l -p [-s -g] (setting breakpoint by source location)
+ // 2). -a [-s -g] (setting breakpoint by address)
+ // 3). -n [-s -g] (setting breakpoint by function name)
+ // 4). -r [-s -g] (setting breakpoint by function name regular expression)
+ // 5). -p -f (setting a breakpoint by comparing a reg-exp to source text)
+ // 6). -E [-w -h] (setting a breakpoint for exceptions for a given language.)
+
+ BreakpointSetType break_type = eSetTypeInvalid;
+
+ if (m_options.m_line_num != 0)
+ break_type = eSetTypeFileAndLine;
+ else if (m_options.m_load_addr != LLDB_INVALID_ADDRESS)
+ break_type = eSetTypeAddress;
+ else if (!m_options.m_func_names.empty())
+ break_type = eSetTypeFunctionName;
+ else if (!m_options.m_func_regexp.empty())
+ break_type = eSetTypeFunctionRegexp;
+ else if (!m_options.m_source_text_regexp.empty())
+ break_type = eSetTypeSourceRegexp;
+ else if (m_options.m_language != eLanguageTypeUnknown)
+ break_type = eSetTypeException;
+
+ Breakpoint *bp = NULL;
+ FileSpec module_spec;
+ const bool internal = false;
+
+ switch (break_type)
+ {
+ case eSetTypeFileAndLine: // Breakpoint by source position
+ {
+ FileSpec file;
+ const size_t num_files = m_options.m_filenames.GetSize();
+ if (num_files == 0)
+ {
+ if (!GetDefaultFile (target, file, result))
+ {
+ result.AppendError("No file supplied and no default file available.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else if (num_files > 1)
+ {
+ result.AppendError("Only one file at a time is allowed for file and line breakpoints.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ file = m_options.m_filenames.GetFileSpecAtIndex(0);
+
+ // Only check for inline functions if
+ LazyBool check_inlines = eLazyBoolCalculate;
+
+ bp = target->CreateBreakpoint (&(m_options.m_modules),
+ file,
+ m_options.m_line_num,
+ check_inlines,
+ m_options.m_skip_prologue,
+ internal).get();
+ }
+ break;
+
+ case eSetTypeAddress: // Breakpoint by address
+ bp = target->CreateBreakpoint (m_options.m_load_addr, false).get();
+ break;
+
+ case eSetTypeFunctionName: // Breakpoint by function name
+ {
+ uint32_t name_type_mask = m_options.m_func_name_type_mask;
+
+ if (name_type_mask == 0)
+ name_type_mask = eFunctionNameTypeAuto;
+
+ bp = target->CreateBreakpoint (&(m_options.m_modules),
+ &(m_options.m_filenames),
+ m_options.m_func_names,
+ name_type_mask,
+ m_options.m_skip_prologue,
+ internal).get();
+ }
+ break;
+
+ case eSetTypeFunctionRegexp: // Breakpoint by regular expression function name
+ {
+ RegularExpression regexp(m_options.m_func_regexp.c_str());
+ if (!regexp.IsValid())
+ {
+ char err_str[1024];
+ regexp.GetErrorAsCString(err_str, sizeof(err_str));
+ result.AppendErrorWithFormat("Function name regular expression could not be compiled: \"%s\"",
+ err_str);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ bp = target->CreateFuncRegexBreakpoint (&(m_options.m_modules),
+ &(m_options.m_filenames),
+ regexp,
+ m_options.m_skip_prologue,
+ internal).get();
+ }
+ break;
+ case eSetTypeSourceRegexp: // Breakpoint by regexp on source text.
+ {
+ const size_t num_files = m_options.m_filenames.GetSize();
+
+ if (num_files == 0)
+ {
+ FileSpec file;
+ if (!GetDefaultFile (target, file, result))
+ {
+ result.AppendError ("No files provided and could not find default file.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ m_options.m_filenames.Append (file);
+ }
+ }
+
+ RegularExpression regexp(m_options.m_source_text_regexp.c_str());
+ if (!regexp.IsValid())
+ {
+ char err_str[1024];
+ regexp.GetErrorAsCString(err_str, sizeof(err_str));
+ result.AppendErrorWithFormat("Source text regular expression could not be compiled: \"%s\"",
+ err_str);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ bp = target->CreateSourceRegexBreakpoint (&(m_options.m_modules), &(m_options.m_filenames), regexp).get();
+ }
+ break;
+ case eSetTypeException:
+ {
+ bp = target->CreateExceptionBreakpoint (m_options.m_language, m_options.m_catch_bp, m_options.m_throw_bp).get();
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Now set the various options that were passed in:
+ if (bp)
+ {
+ if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID)
+ bp->SetThreadID (m_options.m_thread_id);
+
+ if (m_options.m_thread_index != UINT32_MAX)
+ bp->GetOptions()->GetThreadSpec()->SetIndex(m_options.m_thread_index);
+
+ if (!m_options.m_thread_name.empty())
+ bp->GetOptions()->GetThreadSpec()->SetName(m_options.m_thread_name.c_str());
+
+ if (!m_options.m_queue_name.empty())
+ bp->GetOptions()->GetThreadSpec()->SetQueueName(m_options.m_queue_name.c_str());
+
+ if (m_options.m_ignore_count != 0)
+ bp->GetOptions()->SetIgnoreCount(m_options.m_ignore_count);
+
+ if (!m_options.m_condition.empty())
+ bp->GetOptions()->SetCondition(m_options.m_condition.c_str());
+
+ bp->SetOneShot (m_options.m_one_shot);
+ }
+
+ if (bp)
+ {
+ Stream &output_stream = result.GetOutputStream();
+ const bool show_locations = false;
+ bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial, show_locations);
+ // Don't print out this warning for exception breakpoints. They can get set before the target
+ // is set, but we won't know how to actually set the breakpoint till we run.
+ if (bp->GetNumLocations() == 0 && break_type != eSetTypeException)
+ output_stream.Printf ("WARNING: Unable to resolve breakpoint to any actual locations.\n");
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else if (!bp)
+ {
+ result.AppendError ("Breakpoint creation failed: No breakpoint created.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ bool
+ GetDefaultFile (Target *target, FileSpec &file, CommandReturnObject &result)
+ {
+ uint32_t default_line;
+ // First use the Source Manager's default file.
+ // Then use the current stack frame's file.
+ if (!target->GetSourceManager().GetDefaultFileAndLine(file, default_line))
+ {
+ StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
+ if (cur_frame == NULL)
+ {
+ result.AppendError ("No selected frame to use to find the default file.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else if (!cur_frame->HasDebugInformation())
+ {
+ result.AppendError ("Cannot use the selected frame to find the default file, it has no debug info.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ const SymbolContext &sc = cur_frame->GetSymbolContext (eSymbolContextLineEntry);
+ if (sc.line_entry.file)
+ {
+ file = sc.line_entry.file;
+ }
+ else
+ {
+ result.AppendError ("Can't find the file for the selected frame to use as the default file.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ CommandOptions m_options;
+};
+// If an additional option set beyond LLDB_OPTION_SET_10 is added, make sure to
+// update the numbers passed to LLDB_OPT_SET_FROM_TO(...) appropriately.
+#define LLDB_OPT_FILE ( LLDB_OPT_SET_FROM_TO(1, 9) & ~LLDB_OPT_SET_2 )
+#define LLDB_OPT_NOT_10 ( LLDB_OPT_SET_FROM_TO(1, 10) & ~LLDB_OPT_SET_10 )
+#define LLDB_OPT_SKIP_PROLOGUE ( LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3,8) )
+
+OptionDefinition
+CommandObjectBreakpointSet::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_NOT_10, false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName,
+ "Set the breakpoint only in this shared library. "
+ "Can repeat this option multiple times to specify multiple shared libraries."},
+
+ { LLDB_OPT_SET_ALL, false, "ignore-count", 'i', required_argument, NULL, 0, eArgTypeCount,
+ "Set the number of times this breakpoint is skipped before stopping." },
+
+ { LLDB_OPT_SET_ALL, false, "one-shot", 'o', no_argument, NULL, 0, eArgTypeNone,
+ "The breakpoint is deleted the first time it causes a stop." },
+
+ { LLDB_OPT_SET_ALL, false, "condition", 'c', required_argument, NULL, 0, eArgTypeExpression,
+ "The breakpoint stops only if this condition expression evaluates to true."},
+
+ { LLDB_OPT_SET_ALL, false, "thread-index", 'x', required_argument, NULL, 0, eArgTypeThreadIndex,
+ "The breakpoint stops only for the thread whose indeX matches this argument."},
+
+ { LLDB_OPT_SET_ALL, false, "thread-id", 't', required_argument, NULL, 0, eArgTypeThreadID,
+ "The breakpoint stops only for the thread whose TID matches this argument."},
+
+ { LLDB_OPT_SET_ALL, false, "thread-name", 'T', required_argument, NULL, 0, eArgTypeThreadName,
+ "The breakpoint stops only for the thread whose thread name matches this argument."},
+
+ { LLDB_OPT_SET_ALL, false, "queue-name", 'q', required_argument, NULL, 0, eArgTypeQueueName,
+ "The breakpoint stops only for threads in the queue whose name is given by this argument."},
+
+ { LLDB_OPT_FILE, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
+ "Specifies the source file in which to set this breakpoint. "
+ "Note, by default lldb only looks for files that are #included if they use the standard include file extensions. "
+ "To set breakpoints on .c/.cpp/.m/.mm files that are #included, set target.inline-breakpoint-strategy"
+ " to \"always\"."},
+
+ { LLDB_OPT_SET_1, true, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum,
+ "Specifies the line number on which to set this breakpoint."},
+
+ // Comment out this option for the moment, as we don't actually use it, but will in the future.
+ // This way users won't see it, but the infrastructure is left in place.
+ // { 0, false, "column", 'C', required_argument, NULL, "<column>",
+ // "Set the breakpoint by source location at this particular column."},
+
+ { LLDB_OPT_SET_2, true, "address", 'a', required_argument, NULL, 0, eArgTypeAddressOrExpression,
+ "Set the breakpoint by address, at the specified address."},
+
+ { LLDB_OPT_SET_3, true, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
+ "Set the breakpoint by function name. Can be repeated multiple times to make one breakpoint for multiple names" },
+
+ { LLDB_OPT_SET_4, true, "fullname", 'F', required_argument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFullName,
+ "Set the breakpoint by fully qualified function names. For C++ this means namespaces and all arguments, and "
+ "for Objective C this means a full function prototype with class and selector. "
+ "Can be repeated multiple times to make one breakpoint for multiple names." },
+
+ { LLDB_OPT_SET_5, true, "selector", 'S', required_argument, NULL, 0, eArgTypeSelector,
+ "Set the breakpoint by ObjC selector name. Can be repeated multiple times to make one breakpoint for multiple Selectors." },
+
+ { LLDB_OPT_SET_6, true, "method", 'M', required_argument, NULL, 0, eArgTypeMethod,
+ "Set the breakpoint by C++ method names. Can be repeated multiple times to make one breakpoint for multiple methods." },
+
+ { LLDB_OPT_SET_7, true, "func-regex", 'r', required_argument, NULL, 0, eArgTypeRegularExpression,
+ "Set the breakpoint by function name, evaluating a regular-expression to find the function name(s)." },
+
+ { LLDB_OPT_SET_8, true, "basename", 'b', required_argument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
+ "Set the breakpoint by function basename (C++ namespaces and arguments will be ignored). "
+ "Can be repeated multiple times to make one breakpoint for multiple symbols." },
+
+ { LLDB_OPT_SET_9, true, "source-pattern-regexp", 'p', required_argument, NULL, 0, eArgTypeRegularExpression,
+ "Set the breakpoint by specifying a regular expression which is matched against the source text in a source file or files "
+ "specified with the -f option. The -f option can be specified more than once. "
+ "If no source files are specified, uses the current \"default source file\"" },
+
+ { LLDB_OPT_SET_10, true, "language-exception", 'E', required_argument, NULL, 0, eArgTypeLanguage,
+ "Set the breakpoint on exceptions thrown by the specified language (without options, on throw but not catch.)" },
+
+ { LLDB_OPT_SET_10, false, "on-throw", 'w', required_argument, NULL, 0, eArgTypeBoolean,
+ "Set the breakpoint on exception throW." },
+
+ { LLDB_OPT_SET_10, false, "on-catch", 'h', required_argument, NULL, 0, eArgTypeBoolean,
+ "Set the breakpoint on exception catcH." },
+
+ { LLDB_OPT_SKIP_PROLOGUE, false, "skip-prologue", 'K', required_argument, NULL, 0, eArgTypeBoolean,
+ "sKip the prologue if the breakpoint is at the beginning of a function. If not set the target.skip-prologue setting is used." },
+
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointModify
+//-------------------------------------------------------------------------
+#pragma mark Modify
+
+class CommandObjectBreakpointModify : public CommandObjectParsed
+{
+public:
+
+ CommandObjectBreakpointModify (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "breakpoint modify",
+ "Modify the options on a breakpoint or set of breakpoints in the executable. "
+ "If no breakpoint is specified, acts on the last created breakpoint. "
+ "With the exception of -e, -d and -i, passing an empty argument clears the modification.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ virtual
+ ~CommandObjectBreakpointModify () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_ignore_count (0),
+ m_thread_id(LLDB_INVALID_THREAD_ID),
+ m_thread_id_passed(false),
+ m_thread_index (UINT32_MAX),
+ m_thread_index_passed(false),
+ m_thread_name(),
+ m_queue_name(),
+ m_condition (),
+ m_one_shot (false),
+ m_enable_passed (false),
+ m_enable_value (false),
+ m_name_passed (false),
+ m_queue_passed (false),
+ m_condition_passed (false),
+ m_one_shot_passed (false)
+ {
+ }
+
+ virtual
+ ~CommandOptions () {}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'c':
+ if (option_arg != NULL)
+ m_condition.assign (option_arg);
+ else
+ m_condition.clear();
+ m_condition_passed = true;
+ break;
+ case 'd':
+ m_enable_passed = true;
+ m_enable_value = false;
+ break;
+ case 'e':
+ m_enable_passed = true;
+ m_enable_value = true;
+ break;
+ case 'i':
+ {
+ m_ignore_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0);
+ if (m_ignore_count == UINT32_MAX)
+ error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg);
+ }
+ break;
+ case 'o':
+ {
+ bool value, success;
+ value = Args::StringToBoolean(option_arg, false, &success);
+ if (success)
+ {
+ m_one_shot_passed = true;
+ m_one_shot = value;
+ }
+ else
+ error.SetErrorStringWithFormat("invalid boolean value '%s' passed for -o option", option_arg);
+ }
+ break;
+ case 't' :
+ {
+ if (option_arg[0] == '\0')
+ {
+ m_thread_id = LLDB_INVALID_THREAD_ID;
+ m_thread_id_passed = true;
+ }
+ else
+ {
+ m_thread_id = Args::StringToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0);
+ if (m_thread_id == LLDB_INVALID_THREAD_ID)
+ error.SetErrorStringWithFormat ("invalid thread id string '%s'", option_arg);
+ else
+ m_thread_id_passed = true;
+ }
+ }
+ break;
+ case 'T':
+ if (option_arg != NULL)
+ m_thread_name.assign (option_arg);
+ else
+ m_thread_name.clear();
+ m_name_passed = true;
+ break;
+ case 'q':
+ if (option_arg != NULL)
+ m_queue_name.assign (option_arg);
+ else
+ m_queue_name.clear();
+ m_queue_passed = true;
+ break;
+ case 'x':
+ {
+ if (option_arg[0] == '\n')
+ {
+ m_thread_index = UINT32_MAX;
+ m_thread_index_passed = true;
+ }
+ else
+ {
+ m_thread_index = Args::StringToUInt32 (option_arg, UINT32_MAX, 0);
+ if (m_thread_id == UINT32_MAX)
+ error.SetErrorStringWithFormat ("invalid thread index string '%s'", option_arg);
+ else
+ m_thread_index_passed = true;
+ }
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+ void
+ OptionParsingStarting ()
+ {
+ m_ignore_count = 0;
+ m_thread_id = LLDB_INVALID_THREAD_ID;
+ m_thread_id_passed = false;
+ m_thread_index = UINT32_MAX;
+ m_thread_index_passed = false;
+ m_thread_name.clear();
+ m_queue_name.clear();
+ m_condition.clear();
+ m_one_shot = false;
+ m_enable_passed = false;
+ m_queue_passed = false;
+ m_name_passed = false;
+ m_condition_passed = false;
+ m_one_shot_passed = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ uint32_t m_ignore_count;
+ lldb::tid_t m_thread_id;
+ bool m_thread_id_passed;
+ uint32_t m_thread_index;
+ bool m_thread_index_passed;
+ std::string m_thread_name;
+ std::string m_queue_name;
+ std::string m_condition;
+ bool m_one_shot;
+ bool m_enable_passed;
+ bool m_enable_value;
+ bool m_name_passed;
+ bool m_queue_passed;
+ bool m_condition_passed;
+ bool m_one_shot_passed;
+
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No existing target or breakpoints.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Mutex::Locker locker;
+ target->GetBreakpointList().GetListMutex(locker);
+
+ BreakpointIDList valid_bp_ids;
+
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ const size_t count = valid_bp_ids.GetSize();
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+
+ if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
+ {
+ BreakpointLocation *location = bp->FindLocationByID (cur_bp_id.GetLocationID()).get();
+ if (location)
+ {
+ if (m_options.m_thread_id_passed)
+ location->SetThreadID (m_options.m_thread_id);
+
+ if (m_options.m_thread_index_passed)
+ location->SetThreadIndex(m_options.m_thread_index);
+
+ if (m_options.m_name_passed)
+ location->SetThreadName(m_options.m_thread_name.c_str());
+
+ if (m_options.m_queue_passed)
+ location->SetQueueName(m_options.m_queue_name.c_str());
+
+ if (m_options.m_ignore_count != 0)
+ location->SetIgnoreCount(m_options.m_ignore_count);
+
+ if (m_options.m_enable_passed)
+ location->SetEnabled (m_options.m_enable_value);
+
+ if (m_options.m_condition_passed)
+ location->SetCondition (m_options.m_condition.c_str());
+ }
+ }
+ else
+ {
+ if (m_options.m_thread_id_passed)
+ bp->SetThreadID (m_options.m_thread_id);
+
+ if (m_options.m_thread_index_passed)
+ bp->SetThreadIndex(m_options.m_thread_index);
+
+ if (m_options.m_name_passed)
+ bp->SetThreadName(m_options.m_thread_name.c_str());
+
+ if (m_options.m_queue_passed)
+ bp->SetQueueName(m_options.m_queue_name.c_str());
+
+ if (m_options.m_ignore_count != 0)
+ bp->SetIgnoreCount(m_options.m_ignore_count);
+
+ if (m_options.m_enable_passed)
+ bp->SetEnabled (m_options.m_enable_value);
+
+ if (m_options.m_condition_passed)
+ bp->SetCondition (m_options.m_condition.c_str());
+ }
+ }
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+};
+
+#pragma mark Modify::CommandOptions
+OptionDefinition
+CommandObjectBreakpointModify::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "ignore-count", 'i', required_argument, NULL, 0, eArgTypeCount, "Set the number of times this breakpoint is skipped before stopping." },
+{ LLDB_OPT_SET_ALL, false, "one-shot", 'o', required_argument, NULL, 0, eArgTypeBoolean, "The breakpoint is deleted the first time it stop causes a stop." },
+{ LLDB_OPT_SET_ALL, false, "thread-index", 'x', required_argument, NULL, 0, eArgTypeThreadIndex, "The breakpoint stops only for the thread whose index matches this argument."},
+{ LLDB_OPT_SET_ALL, false, "thread-id", 't', required_argument, NULL, 0, eArgTypeThreadID, "The breakpoint stops only for the thread whose TID matches this argument."},
+{ LLDB_OPT_SET_ALL, false, "thread-name", 'T', required_argument, NULL, 0, eArgTypeThreadName, "The breakpoint stops only for the thread whose thread name matches this argument."},
+{ LLDB_OPT_SET_ALL, false, "queue-name", 'q', required_argument, NULL, 0, eArgTypeQueueName, "The breakpoint stops only for threads in the queue whose name is given by this argument."},
+{ LLDB_OPT_SET_ALL, false, "condition", 'c', required_argument, NULL, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true."},
+{ LLDB_OPT_SET_1, false, "enable", 'e', no_argument, NULL, 0, eArgTypeNone, "Enable the breakpoint."},
+{ LLDB_OPT_SET_2, false, "disable", 'd', no_argument, NULL, 0, eArgTypeNone, "Disable the breakpoint."},
+{ 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointEnable
+//-------------------------------------------------------------------------
+#pragma mark Enable
+
+class CommandObjectBreakpointEnable : public CommandObjectParsed
+{
+public:
+ CommandObjectBreakpointEnable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "enable",
+ "Enable the specified disabled breakpoint(s). If no breakpoints are specified, enable all of them.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ virtual
+ ~CommandObjectBreakpointEnable () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No existing target or breakpoints.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Mutex::Locker locker;
+ target->GetBreakpointList().GetListMutex(locker);
+
+ const BreakpointList &breakpoints = target->GetBreakpointList();
+
+ size_t num_breakpoints = breakpoints.GetSize();
+
+ if (num_breakpoints == 0)
+ {
+ result.AppendError ("No breakpoints exist to be enabled.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // No breakpoint selected; enable all currently set breakpoints.
+ target->EnableAllBreakpoints ();
+ result.AppendMessageWithFormat ("All breakpoints enabled. (%lu breakpoints)\n", num_breakpoints);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular breakpoint selected; enable that breakpoint.
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ int enable_count = 0;
+ int loc_count = 0;
+ const size_t count = valid_bp_ids.GetSize();
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+
+ if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
+ {
+ BreakpointLocation *location = breakpoint->FindLocationByID (cur_bp_id.GetLocationID()).get();
+ if (location)
+ {
+ location->SetEnabled (true);
+ ++loc_count;
+ }
+ }
+ else
+ {
+ breakpoint->SetEnabled (true);
+ ++enable_count;
+ }
+ }
+ }
+ result.AppendMessageWithFormat ("%d breakpoints enabled.\n", enable_count + loc_count);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointDisable
+//-------------------------------------------------------------------------
+#pragma mark Disable
+
+class CommandObjectBreakpointDisable : public CommandObjectParsed
+{
+public:
+ CommandObjectBreakpointDisable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "breakpoint disable",
+ "Disable the specified breakpoint(s) without removing it/them. If no breakpoints are specified, disable them all.",
+ NULL)
+ {
+ SetHelpLong(
+"Disable the specified breakpoint(s) without removing it/them. \n\
+If no breakpoints are specified, disable them all.\n\
+\n\
+Note: disabling a breakpoint will cause none of its locations to be hit\n\
+regardless of whether they are enabled or disabled. So the sequence: \n\
+\n\
+ (lldb) break disable 1\n\
+ (lldb) break enable 1.1\n\
+\n\
+will NOT cause location 1.1 to get hit. To achieve that, do:\n\
+\n\
+ (lldb) break disable 1.*\n\
+ (lldb) break enable 1.1\n\
+\n\
+The first command disables all the locations of breakpoint 1, \n\
+the second re-enables the first location."
+ );
+
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back (arg);
+
+ }
+
+
+ virtual
+ ~CommandObjectBreakpointDisable () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No existing target or breakpoints.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Mutex::Locker locker;
+ target->GetBreakpointList().GetListMutex(locker);
+
+ const BreakpointList &breakpoints = target->GetBreakpointList();
+ size_t num_breakpoints = breakpoints.GetSize();
+
+ if (num_breakpoints == 0)
+ {
+ result.AppendError ("No breakpoints exist to be disabled.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // No breakpoint selected; disable all currently set breakpoints.
+ target->DisableAllBreakpoints ();
+ result.AppendMessageWithFormat ("All breakpoints disabled. (%lu breakpoints)\n", num_breakpoints);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular breakpoint selected; disable that breakpoint.
+ BreakpointIDList valid_bp_ids;
+
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ int disable_count = 0;
+ int loc_count = 0;
+ const size_t count = valid_bp_ids.GetSize();
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+
+ if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
+ {
+ BreakpointLocation *location = breakpoint->FindLocationByID (cur_bp_id.GetLocationID()).get();
+ if (location)
+ {
+ location->SetEnabled (false);
+ ++loc_count;
+ }
+ }
+ else
+ {
+ breakpoint->SetEnabled (false);
+ ++disable_count;
+ }
+ }
+ }
+ result.AppendMessageWithFormat ("%d breakpoints disabled.\n", disable_count + loc_count);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointList
+//-------------------------------------------------------------------------
+#pragma mark List
+
+class CommandObjectBreakpointList : public CommandObjectParsed
+{
+public:
+ CommandObjectBreakpointList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "breakpoint list",
+ "List some or all breakpoints at configurable levels of detail.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData bp_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ bp_id_arg.arg_type = eArgTypeBreakpointID;
+ bp_id_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (bp_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ virtual
+ ~CommandObjectBreakpointList () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_level (lldb::eDescriptionLevelBrief) // Breakpoint List defaults to brief descriptions
+ {
+ }
+
+ virtual
+ ~CommandOptions () {}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'b':
+ m_level = lldb::eDescriptionLevelBrief;
+ break;
+ case 'f':
+ m_level = lldb::eDescriptionLevelFull;
+ break;
+ case 'v':
+ m_level = lldb::eDescriptionLevelVerbose;
+ break;
+ case 'i':
+ m_internal = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_level = lldb::eDescriptionLevelFull;
+ m_internal = false;
+ }
+
+ const OptionDefinition *
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ lldb::DescriptionLevel m_level;
+
+ bool m_internal;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No current target or breakpoints.");
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+ const BreakpointList &breakpoints = target->GetBreakpointList(m_options.m_internal);
+ Mutex::Locker locker;
+ target->GetBreakpointList(m_options.m_internal).GetListMutex(locker);
+
+ size_t num_breakpoints = breakpoints.GetSize();
+
+ if (num_breakpoints == 0)
+ {
+ result.AppendMessage ("No breakpoints currently set.");
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+ Stream &output_stream = result.GetOutputStream();
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // No breakpoint selected; show info about all currently set breakpoints.
+ result.AppendMessage ("Current breakpoints:");
+ for (size_t i = 0; i < num_breakpoints; ++i)
+ {
+ Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex (i).get();
+ AddBreakpointDescription (&output_stream, breakpoint, m_options.m_level);
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular breakpoints selected; show info about that breakpoint.
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+ Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ AddBreakpointDescription (&output_stream, breakpoint, m_options.m_level);
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("Invalid breakpoint id.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+};
+
+#pragma mark List::CommandOptions
+OptionDefinition
+CommandObjectBreakpointList::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "internal", 'i', no_argument, NULL, 0, eArgTypeNone,
+ "Show debugger internal breakpoints" },
+
+ { LLDB_OPT_SET_1, false, "brief", 'b', no_argument, NULL, 0, eArgTypeNone,
+ "Give a brief description of the breakpoint (no location info)."},
+
+ // FIXME: We need to add an "internal" command, and then add this sort of thing to it.
+ // But I need to see it for now, and don't want to wait.
+ { LLDB_OPT_SET_2, false, "full", 'f', no_argument, NULL, 0, eArgTypeNone,
+ "Give a full description of the breakpoint and its locations."},
+
+ { LLDB_OPT_SET_3, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone,
+ "Explain everything we know about the breakpoint (for debugging debugger bugs)." },
+
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointClear
+//-------------------------------------------------------------------------
+#pragma mark Clear
+
+class CommandObjectBreakpointClear : public CommandObjectParsed
+{
+public:
+
+ typedef enum BreakpointClearType
+ {
+ eClearTypeInvalid,
+ eClearTypeFileAndLine
+ } BreakpointClearType;
+
+ CommandObjectBreakpointClear (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "breakpoint clear",
+ "Clears a breakpoint or set of breakpoints in the executable.",
+ "breakpoint clear <cmd-options>"),
+ m_options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectBreakpointClear () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_filename (),
+ m_line_num (0)
+ {
+ }
+
+ virtual
+ ~CommandOptions () {}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'f':
+ m_filename.assign (option_arg);
+ break;
+
+ case 'l':
+ m_line_num = Args::StringToUInt32 (option_arg, 0);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_filename.clear();
+ m_line_num = 0;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ std::string m_filename;
+ uint32_t m_line_num;
+
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No existing target or breakpoints.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // The following are the various types of breakpoints that could be cleared:
+ // 1). -f -l (clearing breakpoint by source location)
+
+ BreakpointClearType break_type = eClearTypeInvalid;
+
+ if (m_options.m_line_num != 0)
+ break_type = eClearTypeFileAndLine;
+
+ Mutex::Locker locker;
+ target->GetBreakpointList().GetListMutex(locker);
+
+ BreakpointList &breakpoints = target->GetBreakpointList();
+ size_t num_breakpoints = breakpoints.GetSize();
+
+ // Early return if there's no breakpoint at all.
+ if (num_breakpoints == 0)
+ {
+ result.AppendError ("Breakpoint clear: No breakpoint cleared.");
+ result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
+ }
+
+ // Find matching breakpoints and delete them.
+
+ // First create a copy of all the IDs.
+ std::vector<break_id_t> BreakIDs;
+ for (size_t i = 0; i < num_breakpoints; ++i)
+ BreakIDs.push_back(breakpoints.GetBreakpointAtIndex(i).get()->GetID());
+
+ int num_cleared = 0;
+ StreamString ss;
+ switch (break_type)
+ {
+ case eClearTypeFileAndLine: // Breakpoint by source position
+ {
+ const ConstString filename(m_options.m_filename.c_str());
+ BreakpointLocationCollection loc_coll;
+
+ for (size_t i = 0; i < num_breakpoints; ++i)
+ {
+ Breakpoint *bp = breakpoints.FindBreakpointByID(BreakIDs[i]).get();
+
+ if (bp->GetMatchingFileLine(filename, m_options.m_line_num, loc_coll))
+ {
+ // If the collection size is 0, it's a full match and we can just remove the breakpoint.
+ if (loc_coll.GetSize() == 0)
+ {
+ bp->GetDescription(&ss, lldb::eDescriptionLevelBrief);
+ ss.EOL();
+ target->RemoveBreakpointByID (bp->GetID());
+ ++num_cleared;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (num_cleared > 0)
+ {
+ Stream &output_stream = result.GetOutputStream();
+ output_stream.Printf ("%d breakpoints cleared:\n", num_cleared);
+ output_stream << ss.GetData();
+ output_stream.EOL();
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("Breakpoint clear: No breakpoint cleared.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+};
+
+#pragma mark Clear::CommandOptions
+
+OptionDefinition
+CommandObjectBreakpointClear::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
+ "Specify the breakpoint by source location in this particular file."},
+
+ { LLDB_OPT_SET_1, true, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum,
+ "Specify the breakpoint by source location at this particular line."},
+
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointDelete
+//-------------------------------------------------------------------------
+#pragma mark Delete
+
+class CommandObjectBreakpointDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectBreakpointDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "breakpoint delete",
+ "Delete the specified breakpoint(s). If no breakpoints are specified, delete them all.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectBreakpointDelete () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No existing target or breakpoints.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Mutex::Locker locker;
+ target->GetBreakpointList().GetListMutex(locker);
+
+ const BreakpointList &breakpoints = target->GetBreakpointList();
+
+ size_t num_breakpoints = breakpoints.GetSize();
+
+ if (num_breakpoints == 0)
+ {
+ result.AppendError ("No breakpoints exist to be deleted.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ if (!m_interpreter.Confirm ("About to delete all breakpoints, do you want to do that?", true))
+ {
+ result.AppendMessage("Operation cancelled...");
+ }
+ else
+ {
+ target->RemoveAllBreakpoints ();
+ result.AppendMessageWithFormat ("All breakpoints removed. (%lu %s)\n", num_breakpoints, num_breakpoints > 1 ? "breakpoints" : "breakpoint");
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular breakpoint selected; disable that breakpoint.
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ int delete_count = 0;
+ int disable_count = 0;
+ const size_t count = valid_bp_ids.GetSize();
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+
+ if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
+ {
+ if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ BreakpointLocation *location = breakpoint->FindLocationByID (cur_bp_id.GetLocationID()).get();
+ // It makes no sense to try to delete individual locations, so we disable them instead.
+ if (location)
+ {
+ location->SetEnabled (false);
+ ++disable_count;
+ }
+ }
+ else
+ {
+ target->RemoveBreakpointByID (cur_bp_id.GetBreakpointID());
+ ++delete_count;
+ }
+ }
+ }
+ result.AppendMessageWithFormat ("%d breakpoints deleted; %d breakpoint locations disabled.\n",
+ delete_count, disable_count);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordBreakpoint
+//-------------------------------------------------------------------------
+#pragma mark MultiwordBreakpoint
+
+CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "breakpoint",
+ "A set of commands for operating on breakpoints. Also see _regexp-break.",
+ "breakpoint <command> [<command-options>]")
+{
+ CommandObjectSP list_command_object (new CommandObjectBreakpointList (interpreter));
+ CommandObjectSP enable_command_object (new CommandObjectBreakpointEnable (interpreter));
+ CommandObjectSP disable_command_object (new CommandObjectBreakpointDisable (interpreter));
+ CommandObjectSP clear_command_object (new CommandObjectBreakpointClear (interpreter));
+ CommandObjectSP delete_command_object (new CommandObjectBreakpointDelete (interpreter));
+ CommandObjectSP set_command_object (new CommandObjectBreakpointSet (interpreter));
+ CommandObjectSP command_command_object (new CommandObjectBreakpointCommand (interpreter));
+ CommandObjectSP modify_command_object (new CommandObjectBreakpointModify(interpreter));
+
+ list_command_object->SetCommandName ("breakpoint list");
+ enable_command_object->SetCommandName("breakpoint enable");
+ disable_command_object->SetCommandName("breakpoint disable");
+ clear_command_object->SetCommandName("breakpoint clear");
+ delete_command_object->SetCommandName("breakpoint delete");
+ set_command_object->SetCommandName("breakpoint set");
+ command_command_object->SetCommandName ("breakpoint command");
+ modify_command_object->SetCommandName ("breakpoint modify");
+
+ LoadSubCommand ("list", list_command_object);
+ LoadSubCommand ("enable", enable_command_object);
+ LoadSubCommand ("disable", disable_command_object);
+ LoadSubCommand ("clear", clear_command_object);
+ LoadSubCommand ("delete", delete_command_object);
+ LoadSubCommand ("set", set_command_object);
+ LoadSubCommand ("command", command_command_object);
+ LoadSubCommand ("modify", modify_command_object);
+}
+
+CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint ()
+{
+}
+
+void
+CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result,
+ BreakpointIDList *valid_ids)
+{
+ // args can be strings representing 1). integers (for breakpoint ids)
+ // 2). the full breakpoint & location canonical representation
+ // 3). the word "to" or a hyphen, representing a range (in which case there
+ // had *better* be an entry both before & after of one of the first two types.
+ // If args is empty, we will use the last created breakpoint (if there is one.)
+
+ Args temp_args;
+
+ if (args.GetArgumentCount() == 0)
+ {
+ if (target->GetLastCreatedBreakpoint())
+ {
+ valid_ids->AddBreakpointID (BreakpointID(target->GetLastCreatedBreakpoint()->GetID(), LLDB_INVALID_BREAK_ID));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError("No breakpoint specified and no last created breakpoint.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return;
+ }
+
+ // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff directly from the old ARGS to
+ // the new TEMP_ARGS. Do not copy breakpoint id range strings over; instead generate a list of strings for
+ // all the breakpoint ids in the range, and shove all of those breakpoint id strings into TEMP_ARGS.
+
+ BreakpointIDList::FindAndReplaceIDRanges (args, target, result, temp_args);
+
+ // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual BreakpointIDList:
+
+ valid_ids->InsertStringArray (temp_args.GetConstArgumentVector(), temp_args.GetArgumentCount(), result);
+
+ // At this point, all of the breakpoint ids that the user passed in have been converted to breakpoint IDs
+ // and put into valid_ids.
+
+ if (result.Succeeded())
+ {
+ // Now that we've converted everything from args into a list of breakpoint ids, go through our tentative list
+ // of breakpoint id's and verify that they correspond to valid/currently set breakpoints.
+
+ const size_t count = valid_ids->GetSize();
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex (i);
+ Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ if (breakpoint != NULL)
+ {
+ const size_t num_locations = breakpoint->GetNumLocations();
+ if (cur_bp_id.GetLocationID() > num_locations)
+ {
+ StreamString id_str;
+ BreakpointID::GetCanonicalReference (&id_str,
+ cur_bp_id.GetBreakpointID(),
+ cur_bp_id.GetLocationID());
+ i = valid_ids->GetSize() + 1;
+ result.AppendErrorWithFormat ("'%s' is not a currently valid breakpoint/location id.\n",
+ id_str.GetData());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ i = valid_ids->GetSize() + 1;
+ result.AppendErrorWithFormat ("'%d' is not a currently valid breakpoint id.\n", cur_bp_id.GetBreakpointID());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+}
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpoint.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpoint.h
new file mode 100644
index 0000000..2d674b2
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpoint.h
@@ -0,0 +1,47 @@
+//===-- CommandObjectBreakpoint.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_CommandObjectBreakpoint_h_
+#define liblldb_CommandObjectBreakpoint_h_
+
+// C Includes
+// C++ Includes
+
+#include <utility>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Address.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/STLUtils.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordBreakpoint
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordBreakpoint : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordBreakpoint (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordBreakpoint ();
+
+ static void
+ VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result, BreakpointIDList *valid_ids);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectBreakpoint_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
new file mode 100644
index 0000000..c4504a4
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
@@ -0,0 +1,915 @@
+//===-- CommandObjectBreakpointCommand.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
+// C++ Includes
+
+
+#include "CommandObjectBreakpointCommand.h"
+#include "CommandObjectBreakpoint.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Breakpoint/BreakpointIDList.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/State.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointCommandAdd
+//-------------------------------------------------------------------------
+
+
+class CommandObjectBreakpointCommandAdd : public CommandObjectParsed
+{
+public:
+
+ CommandObjectBreakpointCommandAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "add",
+ "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit.",
+ NULL),
+ m_options (interpreter)
+ {
+ SetHelpLong (
+"\nGeneral information about entering breakpoint commands\n\
+------------------------------------------------------\n\
+\n\
+This command will cause you to be prompted to enter the command or set of\n\
+commands you wish to be executed when the specified breakpoint is hit. You\n\
+will be told to enter your command(s), and will see a '> 'prompt. Because\n\
+you can enter one or many commands to be executed when a breakpoint is hit,\n\
+you will continue to be prompted after each new-line that you enter, until you\n\
+enter the word 'DONE', which will cause the commands you have entered to be\n\
+stored with the breakpoint and executed when the breakpoint is hit.\n\
+\n\
+Syntax checking is not necessarily done when breakpoint commands are entered.\n\
+An improperly written breakpoint command will attempt to get executed when the\n\
+breakpoint gets hit, and usually silently fail. If your breakpoint command does\n\
+not appear to be getting executed, go back and check your syntax.\n\
+\n\
+Special information about PYTHON breakpoint commands\n\
+----------------------------------------------------\n\
+\n\
+You may enter either one line of Python, multiple lines of Python (including\n\
+function definitions), or specify a Python function in a module that has already,\n\
+or will be imported. If you enter a single line of Python, that will be passed\n\
+to the Python interpreter 'as is' when the breakpoint gets hit. If you enter\n\
+function definitions, they will be passed to the Python interpreter as soon as\n\
+you finish entering the breakpoint command, and they can be called later (don't\n\
+forget to add calls to them, if you want them called when the breakpoint is\n\
+hit). If you enter multiple lines of Python that are not function definitions,\n\
+they will be collected into a new, automatically generated Python function, and\n\
+a call to the newly generated function will be attached to the breakpoint.\n\
+\n\
+\n\
+This auto-generated function is passed in three arguments:\n\
+\n\
+ frame: a lldb.SBFrame object for the frame which hit breakpoint.\n\
+ bp_loc: a lldb.SBBreakpointLocation object that represents the breakpoint\n\
+ location that was hit.\n\
+ dict: the python session dictionary hit.\n\
+\n\
+When specifying a python function with the --python-function option, you need\n\
+to supply the function name prepended by the module name. So if you import a\n\
+module named 'myutils' that contains a 'breakpoint_callback' function, you would\n\
+specify the option as:\n\
+\n\
+ --python-function myutils.breakpoint_callback\n\
+\n\
+The function itself must have the following prototype:\n\
+\n\
+def breakpoint_callback(frame, bp_loc, dict):\n\
+ # Your code goes here\n\
+\n\
+The arguments are the same as the 3 auto generation function arguments listed\n\
+above. Note that the global variable 'lldb.frame' will NOT be setup when this\n\
+function is called, so be sure to use the 'frame' argument. The 'frame' argument\n\
+can get you to the thread (frame.GetThread()), the thread can get you to the\n\
+process (thread.GetProcess()), and the process can get you back to the target\n\
+(process.GetTarget()).\n\
+\n\
+Important Note: Because loose Python code gets collected into functions, if you\n\
+want to access global variables in the 'loose' code, you need to specify that\n\
+they are global, using the 'global' keyword. Be sure to use correct Python\n\
+syntax, including indentation, when entering Python breakpoint commands.\n\
+\n\
+As a third option, you can pass the name of an already existing Python function\n\
+and that function will be attached to the breakpoint. It will get passed the\n\
+frame and bp_loc arguments mentioned above.\n\
+\n\
+Example Python one-line breakpoint command:\n\
+\n\
+(lldb) breakpoint command add -s python 1\n\
+Enter your Python command(s). Type 'DONE' to end.\n\
+> print \"Hit this breakpoint!\"\n\
+> DONE\n\
+\n\
+As a convenience, this also works for a short Python one-liner:\n\
+(lldb) breakpoint command add -s python 1 -o \"import time; print time.asctime()\"\n\
+(lldb) run\n\
+Launching '.../a.out' (x86_64)\n\
+(lldb) Fri Sep 10 12:17:45 2010\n\
+Process 21778 Stopped\n\
+* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread\n\
+ 36 \n\
+ 37 int c(int val)\n\
+ 38 {\n\
+ 39 -> return val + 3;\n\
+ 40 }\n\
+ 41 \n\
+ 42 int main (int argc, char const *argv[])\n\
+(lldb)\n\
+\n\
+Example multiple line Python breakpoint command, using function definition:\n\
+\n\
+(lldb) breakpoint command add -s python 1\n\
+Enter your Python command(s). Type 'DONE' to end.\n\
+> def breakpoint_output (bp_no):\n\
+> out_string = \"Hit breakpoint number \" + repr (bp_no)\n\
+> print out_string\n\
+> return True\n\
+> breakpoint_output (1)\n\
+> DONE\n\
+\n\
+\n\
+Example multiple line Python breakpoint command, using 'loose' Python:\n\
+\n\
+(lldb) breakpoint command add -s p 1\n\
+Enter your Python command(s). Type 'DONE' to end.\n\
+> global bp_count\n\
+> bp_count = bp_count + 1\n\
+> print \"Hit this breakpoint \" + repr(bp_count) + \" times!\"\n\
+> DONE\n\
+\n\
+In this case, since there is a reference to a global variable,\n\
+'bp_count', you will also need to make sure 'bp_count' exists and is\n\
+initialized:\n\
+\n\
+(lldb) script\n\
+>>> bp_count = 0\n\
+>>> quit()\n\
+\n\
+(lldb)\n\
+\n\
+\n\
+Your Python code, however organized, can optionally return a value.\n\
+If the returned value is False, that tells LLDB not to stop at the breakpoint\n\
+to which the code is associated. Returning anything other than False, or even\n\
+returning None, or even omitting a return statement entirely, will cause\n\
+LLDB to stop.\n\
+\n\
+Final Note: If you get a warning that no breakpoint command was generated, but\n\
+you did not get any syntax errors, you probably forgot to add a call to your\n\
+functions.\n\
+\n\
+Special information about debugger command breakpoint commands\n\
+--------------------------------------------------------------\n\
+\n\
+You may enter any debugger command, exactly as you would at the debugger prompt.\n\
+You may enter as many debugger commands as you like, but do NOT enter more than\n\
+one command per line.\n" );
+
+ CommandArgumentEntry arg;
+ CommandArgumentData bp_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ bp_id_arg.arg_type = eArgTypeBreakpointID;
+ bp_id_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (bp_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectBreakpointCommandAdd () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ void
+ CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+ CommandReturnObject &result)
+ {
+ InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
+ std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
+ if (reader_sp && data_ap.get())
+ {
+ BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
+ bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp);
+
+ Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback,
+ bp_options, // baton
+ eInputReaderGranularityLine, // token size, to pass to callback function
+ "DONE", // end token
+ "> ", // prompt
+ true)); // echo input
+ if (err.Success())
+ {
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ }
+
+ /// Set a one-liner as the callback for the breakpoint.
+ void
+ 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);
+ data_ap->stop_on_error = m_options.m_stop_on_error;
+
+ BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
+ bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp);
+
+ return;
+ }
+
+ static size_t
+ GenerateBreakpointCommandCallback (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ 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:
+ if (reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderGotToken:
+ if (bytes && bytes_len && baton)
+ {
+ BreakpointOptions *bp_options = (BreakpointOptions *) baton;
+ if (bp_options)
+ {
+ Baton *bp_options_baton = bp_options->GetBaton();
+ if (bp_options_baton)
+ ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
+ }
+ }
+ if (!reader.IsDone() && reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ break;
+
+ case eInputReaderInterrupt:
+ {
+ // Finish, and cancel the breakpoint command.
+ reader.SetIsDone (true);
+ BreakpointOptions *bp_options = (BreakpointOptions *) baton;
+ if (bp_options)
+ {
+ Baton *bp_options_baton = bp_options->GetBaton ();
+ if (bp_options_baton)
+ {
+ ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->user_source.Clear();
+ ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->script_source.clear();
+ }
+ }
+ if (!batch_mode)
+ {
+ out_stream->Printf ("Warning: No command attached to breakpoint.\n");
+ out_stream->Flush();
+ }
+ }
+ break;
+
+ case eInputReaderEndOfFile:
+ reader.SetIsDone (true);
+ break;
+
+ case eInputReaderDone:
+ break;
+ }
+
+ return bytes_len;
+ }
+
+ static bool
+ BreakpointOptionsCallbackFunction (void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id)
+ {
+ bool ret_value = true;
+ if (baton == NULL)
+ return true;
+
+
+ BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton;
+ StringList &commands = data->user_source;
+
+ if (commands.GetSize() > 0)
+ {
+ ExecutionContext exe_ctx (context->exe_ctx_ref);
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ CommandReturnObject result;
+ Debugger &debugger = target->GetDebugger();
+ // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously
+ // if the debugger is set up that way.
+
+ StreamSP output_stream (debugger.GetAsyncOutputStream());
+ StreamSP error_stream (debugger.GetAsyncErrorStream());
+ result.SetImmediateOutputStream (output_stream);
+ result.SetImmediateErrorStream (error_stream);
+
+ bool stop_on_continue = true;
+ bool echo_commands = false;
+ bool print_results = true;
+
+ debugger.GetCommandInterpreter().HandleCommands (commands,
+ &exe_ctx,
+ stop_on_continue,
+ data->stop_on_error,
+ echo_commands,
+ print_results,
+ eLazyBoolNo,
+ result);
+ result.GetImmediateOutputStream()->Flush();
+ result.GetImmediateErrorStream()->Flush();
+ }
+ }
+ return ret_value;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_use_commands (false),
+ m_use_script_language (false),
+ m_script_language (eScriptLanguageNone),
+ m_use_one_liner (false),
+ m_one_liner(),
+ m_function_name()
+ {
+ }
+
+ virtual
+ ~CommandOptions () {}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'o':
+ m_use_one_liner = true;
+ m_one_liner = option_arg;
+ break;
+
+ case 's':
+ m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg,
+ g_option_table[option_idx].enum_values,
+ eScriptLanguageNone,
+ error);
+
+ if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault)
+ {
+ m_use_script_language = true;
+ }
+ else
+ {
+ m_use_script_language = false;
+ }
+ break;
+
+ case 'e':
+ {
+ bool success = false;
+ m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg);
+ }
+ break;
+
+ case 'F':
+ {
+ m_use_one_liner = false;
+ m_use_script_language = true;
+ m_function_name.assign(option_arg);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return error;
+ }
+ void
+ OptionParsingStarting ()
+ {
+ m_use_commands = true;
+ m_use_script_language = false;
+ m_script_language = eScriptLanguageNone;
+
+ m_use_one_liner = false;
+ m_stop_on_error = true;
+ m_one_liner.clear();
+ m_function_name.clear();
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_use_commands;
+ bool m_use_script_language;
+ lldb::ScriptLanguage m_script_language;
+
+ // Instance variables to hold the values for one_liner options.
+ bool m_use_one_liner;
+ std::string m_one_liner;
+ bool m_stop_on_error;
+ std::string m_function_name;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+ if (target == NULL)
+ {
+ result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const BreakpointList &breakpoints = target->GetBreakpointList();
+ size_t num_breakpoints = breakpoints.GetSize();
+
+ if (num_breakpoints == 0)
+ {
+ result.AppendError ("No breakpoints exist to have commands added");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_use_script_language == false && m_options.m_function_name.size())
+ {
+ result.AppendError ("need to enable scripting to have a function run as a breakpoint command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ const size_t count = valid_bp_ids.GetSize();
+ if (count > 1)
+ {
+ result.AppendError ("can only add commands to one breakpoint at a time.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+ if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ BreakpointOptions *bp_options = NULL;
+ if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID)
+ {
+ // This breakpoint does not have an associated location.
+ bp_options = bp->GetOptions();
+ }
+ else
+ {
+ BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
+ // This breakpoint does have an associated location.
+ // Get its breakpoint options.
+ if (bp_loc_sp)
+ bp_options = bp_loc_sp->GetLocationOptions();
+ }
+
+ // Skip this breakpoint if bp_options is not good.
+ if (bp_options == NULL) continue;
+
+ // If we are using script language, get the script interpreter
+ // in order to set or collect command callback. Otherwise, call
+ // the methods associated with this object.
+ if (m_options.m_use_script_language)
+ {
+ // Special handling for one-liner specified inline.
+ if (m_options.m_use_one_liner)
+ {
+ m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
+ m_options.m_one_liner.c_str());
+ }
+ // Special handling for using a Python function by name
+ // instead of extending the breakpoint callback data structures, we just automatize
+ // what the user would do manually: make their breakpoint command be a function call
+ else if (m_options.m_function_name.size())
+ {
+ std::string oneliner("return ");
+ oneliner += m_options.m_function_name;
+ oneliner += "(frame, bp_loc, internal_dict)";
+ m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
+ oneliner.c_str());
+ }
+ else
+ {
+ m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options,
+ result);
+ }
+ }
+ else
+ {
+ // Special handling for one-liner specified inline.
+ if (m_options.m_use_one_liner)
+ SetBreakpointCommandCallback (bp_options,
+ m_options.m_one_liner.c_str());
+ else
+ CollectDataForBreakpointCommandCallback (bp_options,
+ result);
+ }
+ }
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+ static const char *g_reader_instructions;
+
+};
+
+const char *
+CommandObjectBreakpointCommandAdd::g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.";
+
+// FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting
+// language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper.
+
+static OptionEnumValueElement
+g_script_option_enumeration[4] =
+{
+ { eScriptLanguageNone, "command", "Commands are in the lldb command interpreter language"},
+ { eScriptLanguagePython, "python", "Commands are in the Python language."},
+ { eSortOrderByName, "default-script", "Commands are in the default scripting language."},
+ { 0, NULL, NULL }
+};
+
+OptionDefinition
+CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "one-liner", 'o', required_argument, NULL, 0, eArgTypeOneLiner,
+ "Specify a one-line breakpoint command inline. Be sure to surround it with quotes." },
+
+ { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', required_argument, NULL, 0, eArgTypeBoolean,
+ "Specify whether breakpoint command execution should terminate on error." },
+
+ { LLDB_OPT_SET_ALL, false, "script-type", 's', required_argument, g_script_option_enumeration, 0, eArgTypeNone,
+ "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
+
+ { LLDB_OPT_SET_2, false, "python-function", 'F', required_argument, NULL, 0, eArgTypePythonFunction,
+ "Give the name of a Python function to run as command for this breakpoint. Be sure to give a module name if appropriate."},
+
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointCommandDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectBreakpointCommandDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectBreakpointCommandDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "delete",
+ "Delete the set of commands from a breakpoint.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData bp_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ bp_id_arg.arg_type = eArgTypeBreakpointID;
+ bp_id_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (bp_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ virtual
+ ~CommandObjectBreakpointCommandDelete () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+ if (target == NULL)
+ {
+ result.AppendError ("There is not a current executable; there are no breakpoints from which to delete commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const BreakpointList &breakpoints = target->GetBreakpointList();
+ size_t num_breakpoints = breakpoints.GetSize();
+
+ if (num_breakpoints == 0)
+ {
+ result.AppendError ("No breakpoints exist to have commands deleted");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ result.AppendError ("No breakpoint specified from which to delete the commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ const size_t count = valid_bp_ids.GetSize();
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+ if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
+ {
+ BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID()));
+ if (bp_loc_sp)
+ bp_loc_sp->ClearCallback();
+ else
+ {
+ result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
+ cur_bp_id.GetBreakpointID(),
+ cur_bp_id.GetLocationID());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ bp->ClearCallback();
+ }
+ }
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointCommandList
+//-------------------------------------------------------------------------
+
+class CommandObjectBreakpointCommandList : public CommandObjectParsed
+{
+public:
+ CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "list",
+ "List the script or set of commands to be executed when the breakpoint is hit.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData bp_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ bp_id_arg.arg_type = eArgTypeBreakpointID;
+ bp_id_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (bp_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectBreakpointCommandList () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+ if (target == NULL)
+ {
+ result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const BreakpointList &breakpoints = target->GetBreakpointList();
+ size_t num_breakpoints = breakpoints.GetSize();
+
+ if (num_breakpoints == 0)
+ {
+ result.AppendError ("No breakpoints exist for which to list commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ result.AppendError ("No breakpoint specified for which to list the commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ const size_t count = valid_bp_ids.GetSize();
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+ if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+
+ if (bp)
+ {
+ const BreakpointOptions *bp_options = NULL;
+ if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
+ {
+ BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
+ if (bp_loc_sp)
+ bp_options = bp_loc_sp->GetOptionsNoCreate();
+ else
+ {
+ result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
+ cur_bp_id.GetBreakpointID(),
+ cur_bp_id.GetLocationID());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ bp_options = bp->GetOptions();
+ }
+
+ if (bp_options)
+ {
+ StreamString id_str;
+ BreakpointID::GetCanonicalReference (&id_str,
+ cur_bp_id.GetBreakpointID(),
+ cur_bp_id.GetLocationID());
+ const Baton *baton = bp_options->GetBaton();
+ if (baton)
+ {
+ result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData());
+ result.GetOutputStream().IndentMore ();
+ baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
+ result.GetOutputStream().IndentLess ();
+ }
+ else
+ {
+ result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n",
+ id_str.GetData());
+ }
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID());
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ }
+ }
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointCommand
+//-------------------------------------------------------------------------
+
+CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "command",
+ "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').",
+ "command <sub-command> [<sub-command-options>] <breakpoint-id>")
+{
+ CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter));
+ CommandObjectSP delete_command_object (new CommandObjectBreakpointCommandDelete (interpreter));
+ CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter));
+
+ add_command_object->SetCommandName ("breakpoint command add");
+ delete_command_object->SetCommandName ("breakpoint command delete");
+ list_command_object->SetCommandName ("breakpoint command list");
+
+ LoadSubCommand ("add", add_command_object);
+ LoadSubCommand ("delete", delete_command_object);
+ LoadSubCommand ("list", list_command_object);
+}
+
+CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
+{
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.h
new file mode 100644
index 0000000..afedb76
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.h
@@ -0,0 +1,46 @@
+//===-- CommandObjectBreakpointCommand.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_CommandObjectBreakpointCommand_h_
+#define liblldb_CommandObjectBreakpointCommand_h_
+
+// C Includes
+// C++ Includes
+
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-types.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordBreakpoint
+//-------------------------------------------------------------------------
+
+class CommandObjectBreakpointCommand : public CommandObjectMultiword
+{
+public:
+ CommandObjectBreakpointCommand (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectBreakpointCommand ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectBreakpointCommand_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp
new file mode 100644
index 0000000..4699aa6
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp
@@ -0,0 +1,2021 @@
+//===-- CommandObjectSource.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 "CommandObjectCommands.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "llvm/ADT/StringRef.h"
+
+// Project includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/InputReaderEZ.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandHistory.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObjectRegexCommand.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionValueBoolean.h"
+#include "lldb/Interpreter/OptionValueUInt64.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsSource
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsHistory : public CommandObjectParsed
+{
+public:
+ CommandObjectCommandsHistory(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command history",
+ "Dump the history of commands in this session.",
+ NULL),
+ m_options (interpreter)
+ {
+ }
+
+ ~CommandObjectCommandsHistory () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_start_idx(0),
+ m_stop_idx(0),
+ m_count(0),
+ m_clear(false)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'c':
+ error = m_count.SetValueFromCString(option_arg,eVarSetOperationAssign);
+ break;
+ case 's':
+ if (option_arg && strcmp("end", option_arg) == 0)
+ {
+ m_start_idx.SetCurrentValue(UINT64_MAX);
+ m_start_idx.SetOptionWasSet();
+ }
+ else
+ error = m_start_idx.SetValueFromCString(option_arg,eVarSetOperationAssign);
+ break;
+ case 'e':
+ error = m_stop_idx.SetValueFromCString(option_arg,eVarSetOperationAssign);
+ break;
+ case 'C':
+ m_clear.SetCurrentValue(true);
+ m_clear.SetOptionWasSet();
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_start_idx.Clear();
+ m_stop_idx.Clear();
+ m_count.Clear();
+ m_clear.Clear();
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ OptionValueUInt64 m_start_idx;
+ OptionValueUInt64 m_stop_idx;
+ OptionValueUInt64 m_count;
+ OptionValueBoolean m_clear;
+ };
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ if (m_options.m_clear.GetCurrentValue() && m_options.m_clear.OptionWasSet())
+ {
+ m_interpreter.GetCommandHistory().Clear();
+ result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ if (m_options.m_start_idx.OptionWasSet() && m_options.m_stop_idx.OptionWasSet() && m_options.m_count.OptionWasSet())
+ {
+ result.AppendError("--count, --start-index and --end-index cannot be all specified in the same invocation");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ }
+ else
+ {
+ std::pair<bool,uint64_t> start_idx = {m_options.m_start_idx.OptionWasSet(),m_options.m_start_idx.GetCurrentValue()};
+ std::pair<bool,uint64_t> stop_idx = {m_options.m_stop_idx.OptionWasSet(),m_options.m_stop_idx.GetCurrentValue()};
+ std::pair<bool,uint64_t> count = {m_options.m_count.OptionWasSet(),m_options.m_count.GetCurrentValue()};
+
+ const CommandHistory& history(m_interpreter.GetCommandHistory());
+
+ if (start_idx.first && start_idx.second == UINT64_MAX)
+ {
+ if (count.first)
+ {
+ start_idx.second = history.GetSize() - count.second;
+ stop_idx.second = history.GetSize() - 1;
+ }
+ else if (stop_idx.first)
+ {
+ start_idx.second = stop_idx.second;
+ stop_idx.second = history.GetSize() - 1;
+ }
+ else
+ {
+ start_idx.second = 0;
+ stop_idx.second = history.GetSize() - 1;
+ }
+ }
+ else
+ {
+ if (!start_idx.first && !stop_idx.first && !count.first)
+ {
+ start_idx.second = 0;
+ stop_idx.second = history.GetSize() - 1;
+ }
+ else if (start_idx.first)
+ {
+ if (count.first)
+ {
+ stop_idx.second = start_idx.second + count.second - 1;
+ }
+ else if (!stop_idx.first)
+ {
+ stop_idx.second = history.GetSize() - 1;
+ }
+ }
+ else if (stop_idx.first)
+ {
+ if (count.first)
+ {
+ if (stop_idx.second >= count.second)
+ start_idx.second = stop_idx.second - count.second + 1;
+ else
+ start_idx.second = 0;
+ }
+ }
+ else /* if (count.first) */
+ {
+ start_idx.second = 0;
+ stop_idx.second = count.second - 1;
+ }
+ }
+ history.Dump(result.GetOutputStream(), start_idx.second, stop_idx.second);
+ }
+ }
+ return result.Succeeded();
+
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectCommandsHistory::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "count", 'c', required_argument, NULL, 0, eArgTypeUnsignedInteger, "How many history commands to print."},
+{ LLDB_OPT_SET_1, false, "start-index", 's', required_argument, NULL, 0, eArgTypeUnsignedInteger, "Index at which to start printing history commands (or end to mean tail mode)."},
+{ LLDB_OPT_SET_1, false, "end-index", 'e', required_argument, NULL, 0, eArgTypeUnsignedInteger, "Index at which to stop printing history commands."},
+{ LLDB_OPT_SET_2, false, "clear", 'C', no_argument, NULL, 0, eArgTypeBoolean, "Clears the current command history."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsSource
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsSource : public CommandObjectParsed
+{
+public:
+ CommandObjectCommandsSource(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command source",
+ "Read in debugger commands from the file <filename> and execute them.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData file_arg;
+
+ // Define the first (and only) variant of this arg.
+ file_arg.arg_type = eArgTypeFilename;
+ file_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (file_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectCommandsSource () {}
+
+ virtual const char*
+ GetRepeatCommand (Args &current_command_args, uint32_t index)
+ {
+ return "";
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eDiskFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_stop_on_error (true)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+ bool success;
+
+ switch (short_option)
+ {
+ case 'e':
+ error = m_stop_on_error.SetValueFromCString(option_arg);
+ break;
+ case 'c':
+ m_stop_on_continue = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for stop-on-continue: %s", option_arg);
+ break;
+ case 's':
+ m_silent_run = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for silent-run: %s", option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_stop_on_error.Clear();
+ m_silent_run = false;
+ m_stop_on_continue = true;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ OptionValueBoolean m_stop_on_error;
+ bool m_silent_run;
+ bool m_stop_on_continue;
+ };
+
+ bool
+ DoExecute(Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 1)
+ {
+ const char *filename = command.GetArgumentAtIndex(0);
+
+ result.AppendMessageWithFormat ("Executing commands in '%s'.\n", filename);
+
+ FileSpec cmd_file (filename, true);
+ ExecutionContext *exe_ctx = NULL; // Just use the default context.
+ bool echo_commands = !m_options.m_silent_run;
+ bool print_results = true;
+ bool stop_on_error = m_options.m_stop_on_error.OptionWasSet() ? (bool)m_options.m_stop_on_error : m_interpreter.GetStopCmdSourceOnError();
+
+ m_interpreter.HandleCommandsFromFile (cmd_file,
+ exe_ctx,
+ m_options.m_stop_on_continue,
+ stop_on_error,
+ echo_commands,
+ print_results,
+ eLazyBoolCalculate,
+ result);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("'%s' takes exactly one executable filename argument.\n", GetCommandName());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+
+ }
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectCommandsSource::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', required_argument, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on error."},
+{ LLDB_OPT_SET_ALL, false, "stop-on-continue", 'c', required_argument, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on continue."},
+{ LLDB_OPT_SET_ALL, false, "silent-run", 's', required_argument, NULL, 0, eArgTypeBoolean, "If true don't echo commands while executing."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#pragma mark CommandObjectCommandsAlias
+//-------------------------------------------------------------------------
+// CommandObjectCommandsAlias
+//-------------------------------------------------------------------------
+
+static const char *g_python_command_instructions = "Enter your Python command(s). Type 'DONE' to end.\n"
+ "You must define a Python function with this signature:\n"
+ "def my_command_impl(debugger, args, result, internal_dict):";
+
+
+class CommandObjectCommandsAlias : public CommandObjectRaw
+{
+
+
+public:
+ CommandObjectCommandsAlias (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "command alias",
+ "Allow users to define their own debugger command abbreviations.",
+ NULL)
+ {
+ SetHelpLong(
+ "'alias' allows the user to create a short-cut or abbreviation for long \n\
+ commands, multi-word commands, and commands that take particular options. \n\
+ Below are some simple examples of how one might use the 'alias' command: \n\
+ \n 'command alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\
+ // command. \n\
+ 'command alias bp breakpoint' // Creates the abbreviation 'bp' for the 'breakpoint' \n\
+ // command. Since breakpoint commands are two-word \n\
+ // commands, the user will still need to enter the \n\
+ // second word after 'bp', e.g. 'bp enable' or \n\
+ // 'bp delete'. \n\
+ 'command alias bpl breakpoint list' // Creates the abbreviation 'bpl' for the \n\
+ // two-word command 'breakpoint list'. \n\
+ \nAn alias can include some options for the command, with the values either \n\
+ filled in at the time the alias is created, or specified as positional \n\
+ arguments, to be filled in when the alias is invoked. The following example \n\
+ shows how to create aliases with options: \n\
+ \n\
+ 'command alias bfl breakpoint set -f %1 -l %2' \n\
+ \nThis creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \n\
+ options already part of the alias. So if the user wants to set a breakpoint \n\
+ by file and line without explicitly having to use the -f and -l options, the \n\
+ user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \n\
+ for the actual arguments that will be passed when the alias command is used. \n\
+ The number in the placeholder refers to the position/order the actual value \n\
+ occupies when the alias is used. All the occurrences of '%1' in the alias \n\
+ will be replaced with the first argument, all the occurrences of '%2' in the \n\
+ alias will be replaced with the second argument, and so on. This also allows \n\
+ actual arguments to be used multiple times within an alias (see 'process \n\
+ launch' example below). \n\
+ Note: the positional arguments must substitute as whole words in the resultant\n\
+ command, so you can't at present do something like:\n\
+ \n\
+ command alias bcppfl breakpoint set -f %1.cpp -l %2\n\
+ \n\
+ to get the file extension \".cpp\" automatically appended. For more complex\n\
+ aliasing, use the \"command regex\" command instead.\n\
+ \nSo in the 'bfl' case, the actual file value will be \n\
+ filled in with the first argument following 'bfl' and the actual line number \n\
+ value will be filled in with the second argument. The user would use this \n\
+ alias as follows: \n\
+ \n (lldb) command alias bfl breakpoint set -f %1 -l %2 \n\
+ <... some time later ...> \n\
+ (lldb) bfl my-file.c 137 \n\
+ \nThis would be the same as if the user had entered \n\
+ 'breakpoint set -f my-file.c -l 137'. \n\
+ \nAnother example: \n\
+ \n (lldb) command alias pltty process launch -s -o %1 -e %1 \n\
+ (lldb) pltty /dev/tty0 \n\
+ // becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\
+ \nIf the user always wanted to pass the same value to a particular option, the \n\
+ alias could be defined with that value directly in the alias as a constant, \n\
+ rather than using a positional placeholder: \n\
+ \n command alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\
+ // 3 of whatever file is indicated. \n");
+
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentEntry arg3;
+ CommandArgumentData alias_arg;
+ CommandArgumentData cmd_arg;
+ CommandArgumentData options_arg;
+
+ // Define the first (and only) variant of this arg.
+ alias_arg.arg_type = eArgTypeAliasName;
+ alias_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (alias_arg);
+
+ // Define the first (and only) variant of this arg.
+ cmd_arg.arg_type = eArgTypeCommandName;
+ cmd_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (cmd_arg);
+
+ // Define the first (and only) variant of this arg.
+ options_arg.arg_type = eArgTypeAliasOptions;
+ options_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg3.push_back (options_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ m_arguments.push_back (arg3);
+ }
+
+ ~CommandObjectCommandsAlias ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *raw_command_line, CommandReturnObject &result)
+ {
+ Args args (raw_command_line);
+ std::string raw_command_string (raw_command_line);
+
+ size_t argc = args.GetArgumentCount();
+
+ if (argc < 2)
+ {
+ result.AppendError ("'alias' requires at least two arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Get the alias command.
+
+ const std::string alias_command = args.GetArgumentAtIndex (0);
+
+ // Strip the new alias name off 'raw_command_string' (leave it on args, which gets passed to 'Execute', which
+ // does the stripping itself.
+ size_t pos = raw_command_string.find (alias_command);
+ if (pos == 0)
+ {
+ raw_command_string = raw_command_string.substr (alias_command.size());
+ pos = raw_command_string.find_first_not_of (' ');
+ if ((pos != std::string::npos) && (pos > 0))
+ raw_command_string = raw_command_string.substr (pos);
+ }
+ else
+ {
+ result.AppendError ("Error parsing command string. No alias created.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+
+ // Verify that the command is alias-able.
+ if (m_interpreter.CommandExists (alias_command.c_str()))
+ {
+ result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
+ alias_command.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Get CommandObject that is being aliased. The command name is read from the front of raw_command_string.
+ // raw_command_string is returned with the name of the command object stripped off the front.
+ CommandObject *cmd_obj = m_interpreter.GetCommandObjectForCommand (raw_command_string);
+
+ if (!cmd_obj)
+ {
+ result.AppendErrorWithFormat ("invalid command given to 'alias'. '%s' does not begin with a valid command."
+ " No alias created.", raw_command_string.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else if (!cmd_obj->WantsRawCommandString ())
+ {
+ // Note that args was initialized with the original command, and has not been updated to this point.
+ // Therefore can we pass it to the version of Execute that does not need/expect raw input in the alias.
+ return HandleAliasingNormalCommand (args, result);
+ }
+ else
+ {
+ return HandleAliasingRawCommand (alias_command, raw_command_string, *cmd_obj, result);
+ }
+ return result.Succeeded();
+ }
+
+ bool
+ HandleAliasingRawCommand (const std::string &alias_command, std::string &raw_command_string, CommandObject &cmd_obj, CommandReturnObject &result)
+ {
+ // Verify & handle any options/arguments passed to the alias command
+
+ OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
+ OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
+
+ CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact (cmd_obj.GetCommandName(), false);
+
+ if (!m_interpreter.ProcessAliasOptionsArgs (cmd_obj_sp, raw_command_string.c_str(), option_arg_vector_sp))
+ {
+ result.AppendError ("Unable to create requested alias.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Create the alias
+ if (m_interpreter.AliasExists (alias_command.c_str())
+ || m_interpreter.UserCommandExists (alias_command.c_str()))
+ {
+ OptionArgVectorSP temp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str()));
+ if (temp_option_arg_sp.get())
+ {
+ if (option_arg_vector->size() == 0)
+ m_interpreter.RemoveAliasOptions (alias_command.c_str());
+ }
+ result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
+ alias_command.c_str());
+ }
+
+ if (cmd_obj_sp)
+ {
+ m_interpreter.AddAlias (alias_command.c_str(), cmd_obj_sp);
+ if (option_arg_vector->size() > 0)
+ m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("Unable to create requested alias.\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded ();
+ }
+
+ bool
+ HandleAliasingNormalCommand (Args& args, CommandReturnObject &result)
+ {
+ size_t argc = args.GetArgumentCount();
+
+ if (argc < 2)
+ {
+ result.AppendError ("'alias' requires at least two arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const std::string alias_command = args.GetArgumentAtIndex(0);
+ const std::string actual_command = args.GetArgumentAtIndex(1);
+
+ args.Shift(); // Shift the alias command word off the argument vector.
+ args.Shift(); // Shift the old command word off the argument vector.
+
+ // Verify that the command is alias'able, and get the appropriate command object.
+
+ if (m_interpreter.CommandExists (alias_command.c_str()))
+ {
+ result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
+ alias_command.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true));
+ CommandObjectSP subcommand_obj_sp;
+ bool use_subcommand = false;
+ if (command_obj_sp.get())
+ {
+ CommandObject *cmd_obj = command_obj_sp.get();
+ CommandObject *sub_cmd_obj = NULL;
+ OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
+ OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
+
+ while (cmd_obj->IsMultiwordObject() && args.GetArgumentCount() > 0)
+ {
+ if (argc >= 3)
+ {
+ const std::string sub_command = args.GetArgumentAtIndex(0);
+ assert (sub_command.length() != 0);
+ subcommand_obj_sp = cmd_obj->GetSubcommandSP (sub_command.c_str());
+ if (subcommand_obj_sp.get())
+ {
+ sub_cmd_obj = subcommand_obj_sp.get();
+ use_subcommand = true;
+ args.Shift(); // Shift the sub_command word off the argument vector.
+ cmd_obj = sub_cmd_obj;
+ }
+ else
+ {
+ result.AppendErrorWithFormat("'%s' is not a valid sub-command of '%s'. "
+ "Unable to create alias.\n",
+ sub_command.c_str(), actual_command.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+
+ // Verify & handle any options/arguments passed to the alias command
+
+ if (args.GetArgumentCount () > 0)
+ {
+ CommandObjectSP tmp_sp = m_interpreter.GetCommandSPExact (cmd_obj->GetCommandName(), false);
+ if (use_subcommand)
+ tmp_sp = m_interpreter.GetCommandSPExact (sub_cmd_obj->GetCommandName(), false);
+
+ std::string args_string;
+ args.GetCommandString (args_string);
+
+ if (!m_interpreter.ProcessAliasOptionsArgs (tmp_sp, args_string.c_str(), option_arg_vector_sp))
+ {
+ result.AppendError ("Unable to create requested alias.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ // Create the alias.
+
+ if (m_interpreter.AliasExists (alias_command.c_str())
+ || m_interpreter.UserCommandExists (alias_command.c_str()))
+ {
+ OptionArgVectorSP tmp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str()));
+ if (tmp_option_arg_sp.get())
+ {
+ if (option_arg_vector->size() == 0)
+ m_interpreter.RemoveAliasOptions (alias_command.c_str());
+ }
+ result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
+ alias_command.c_str());
+ }
+
+ if (use_subcommand)
+ m_interpreter.AddAlias (alias_command.c_str(), subcommand_obj_sp);
+ else
+ m_interpreter.AddAlias (alias_command.c_str(), command_obj_sp);
+ if (option_arg_vector->size() > 0)
+ m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+};
+
+#pragma mark CommandObjectCommandsUnalias
+//-------------------------------------------------------------------------
+// CommandObjectCommandsUnalias
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsUnalias : public CommandObjectParsed
+{
+public:
+ CommandObjectCommandsUnalias (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command unalias",
+ "Allow the user to remove/delete a user-defined command abbreviation.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData alias_arg;
+
+ // Define the first (and only) variant of this arg.
+ alias_arg.arg_type = eArgTypeAliasName;
+ alias_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (alias_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectCommandsUnalias()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ CommandObject::CommandMap::iterator pos;
+ CommandObject *cmd_obj;
+
+ if (args.GetArgumentCount() != 0)
+ {
+ const char *command_name = args.GetArgumentAtIndex(0);
+ cmd_obj = m_interpreter.GetCommandObject(command_name);
+ if (cmd_obj)
+ {
+ if (m_interpreter.CommandExists (command_name))
+ {
+ result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n",
+ command_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+
+ if (m_interpreter.RemoveAlias (command_name) == false)
+ {
+ if (m_interpreter.AliasExists (command_name))
+ result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n",
+ command_name);
+ else
+ result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a "
+ "current list of commands.\n",
+ command_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("must call 'unalias' with a valid alias");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsAddRegex
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectCommandsAddRegex
+
+class CommandObjectCommandsAddRegex : public CommandObjectParsed
+{
+public:
+ CommandObjectCommandsAddRegex (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command regex",
+ "Allow the user to create a regular expression command.",
+ "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
+ m_options (interpreter)
+ {
+ SetHelpLong(
+"This command allows the user to create powerful regular expression commands\n"
+"with substitutions. The regular expressions and substitutions are specified\n"
+"using the regular exression substitution format of:\n"
+"\n"
+" s/<regex>/<subst>/\n"
+"\n"
+"<regex> is a regular expression that can use parenthesis to capture regular\n"
+"expression input and substitute the captured matches in the output using %1\n"
+"for the first match, %2 for the second, and so on.\n"
+"\n"
+"The regular expressions can all be specified on the command line if more than\n"
+"one argument is provided. If just the command name is provided on the command\n"
+"line, then the regular expressions and substitutions can be entered on separate\n"
+" lines, followed by an empty line to terminate the command definition.\n"
+"\n"
+"EXAMPLES\n"
+"\n"
+"The following example will define a regular expression command named 'f' that\n"
+"will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if\n"
+"a number follows 'f':\n"
+"\n"
+" (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/'\n"
+"\n"
+ );
+ }
+
+ ~CommandObjectCommandsAddRegex()
+ {
+ }
+
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ result.AppendError ("usage: 'command regex <command-name> [s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ Error error;
+ const char *name = command.GetArgumentAtIndex(0);
+ m_regex_cmd_ap.reset (new CommandObjectRegexCommand (m_interpreter,
+ name,
+ m_options.GetHelp (),
+ m_options.GetSyntax (),
+ 10));
+
+ if (argc == 1)
+ {
+ InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
+ if (reader_sp)
+ {
+ error =reader_sp->Initialize (CommandObjectCommandsAddRegex::InputReaderCallback,
+ this, // baton
+ eInputReaderGranularityLine, // token size, to pass to callback function
+ NULL, // end token
+ "> ", // prompt
+ true); // echo input
+ if (error.Success())
+ {
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+ }
+ }
+ else
+ {
+ for (size_t arg_idx = 1; arg_idx < argc; ++arg_idx)
+ {
+ llvm::StringRef arg_strref (command.GetArgumentAtIndex(arg_idx));
+ error = AppendRegexSubstitution (arg_strref);
+ if (error.Fail())
+ break;
+ }
+
+ if (error.Success())
+ {
+ AddRegexCommandToInterpreter();
+ }
+ }
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+ Error
+ AppendRegexSubstitution (const llvm::StringRef &regex_sed)
+ {
+ Error error;
+
+ if (m_regex_cmd_ap.get() == NULL)
+ {
+ error.SetErrorStringWithFormat("invalid regular expression command object for: '%.*s'",
+ (int)regex_sed.size(),
+ regex_sed.data());
+ return error;
+ }
+
+ size_t regex_sed_size = regex_sed.size();
+
+ if (regex_sed_size <= 1)
+ {
+ error.SetErrorStringWithFormat("regular expression substitution string is too short: '%.*s'",
+ (int)regex_sed.size(),
+ regex_sed.data());
+ return error;
+ }
+
+ if (regex_sed[0] != 's')
+ {
+ error.SetErrorStringWithFormat("regular expression substitution string doesn't start with 's': '%.*s'",
+ (int)regex_sed.size(),
+ regex_sed.data());
+ return error;
+ }
+ const size_t first_separator_char_pos = 1;
+ // use the char that follows 's' as the regex separator character
+ // so we can have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
+ const char separator_char = regex_sed[first_separator_char_pos];
+ const size_t second_separator_char_pos = regex_sed.find (separator_char, first_separator_char_pos + 1);
+
+ if (second_separator_char_pos == std::string::npos)
+ {
+ error.SetErrorStringWithFormat("missing second '%c' separator char after '%.*s'",
+ separator_char,
+ (int)(regex_sed.size() - first_separator_char_pos - 1),
+ regex_sed.data() + (first_separator_char_pos + 1));
+ return error;
+ }
+
+ const size_t third_separator_char_pos = regex_sed.find (separator_char, second_separator_char_pos + 1);
+
+ if (third_separator_char_pos == std::string::npos)
+ {
+ error.SetErrorStringWithFormat("missing third '%c' separator char after '%.*s'",
+ separator_char,
+ (int)(regex_sed.size() - second_separator_char_pos - 1),
+ regex_sed.data() + (second_separator_char_pos + 1));
+ return error;
+ }
+
+ if (third_separator_char_pos != regex_sed_size - 1)
+ {
+ // Make sure that everything that follows the last regex
+ // separator char
+ if (regex_sed.find_first_not_of("\t\n\v\f\r ", third_separator_char_pos + 1) != std::string::npos)
+ {
+ error.SetErrorStringWithFormat("extra data found after the '%.*s' regular expression substitution string: '%.*s'",
+ (int)third_separator_char_pos + 1,
+ regex_sed.data(),
+ (int)(regex_sed.size() - third_separator_char_pos - 1),
+ regex_sed.data() + (third_separator_char_pos + 1));
+ return error;
+ }
+
+ }
+ else if (first_separator_char_pos + 1 == second_separator_char_pos)
+ {
+ error.SetErrorStringWithFormat("<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
+ separator_char,
+ separator_char,
+ separator_char,
+ (int)regex_sed.size(),
+ regex_sed.data());
+ return error;
+ }
+ else if (second_separator_char_pos + 1 == third_separator_char_pos)
+ {
+ error.SetErrorStringWithFormat("<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
+ separator_char,
+ separator_char,
+ separator_char,
+ (int)regex_sed.size(),
+ regex_sed.data());
+ return error;
+ }
+ std::string regex(regex_sed.substr(first_separator_char_pos + 1, second_separator_char_pos - first_separator_char_pos - 1));
+ std::string subst(regex_sed.substr(second_separator_char_pos + 1, third_separator_char_pos - second_separator_char_pos - 1));
+ m_regex_cmd_ap->AddRegexCommand (regex.c_str(),
+ subst.c_str());
+ return error;
+ }
+
+ void
+ AddRegexCommandToInterpreter()
+ {
+ if (m_regex_cmd_ap.get())
+ {
+ if (m_regex_cmd_ap->HasRegexEntries())
+ {
+ CommandObjectSP cmd_sp (m_regex_cmd_ap.release());
+ m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
+ }
+ }
+ }
+
+ void
+ InputReaderDidCancel()
+ {
+ m_regex_cmd_ap.reset();
+ }
+
+ static size_t
+ InputReaderCallback (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len)
+ {
+ CommandObjectCommandsAddRegex *add_regex_cmd = (CommandObjectCommandsAddRegex *) baton;
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ if (!batch_mode)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream ();
+ out_stream->Printf("%s\n", "Enter regular expressions in the form 's/<regex>/<subst>/' and terminate with an empty line:");
+ out_stream->Flush();
+ }
+ break;
+ case eInputReaderReactivate:
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderGotToken:
+ while (bytes_len > 0 && (bytes[bytes_len-1] == '\r' || bytes[bytes_len-1] == '\n'))
+ --bytes_len;
+ if (bytes_len == 0)
+ reader.SetIsDone(true);
+ else if (bytes)
+ {
+ llvm::StringRef bytes_strref (bytes, bytes_len);
+ Error error (add_regex_cmd->AppendRegexSubstitution (bytes_strref));
+ if (error.Fail())
+ {
+ if (!batch_mode)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ out_stream->Printf("error: %s\n", error.AsCString());
+ out_stream->Flush();
+ }
+ add_regex_cmd->InputReaderDidCancel ();
+ reader.SetIsDone (true);
+ }
+ }
+ break;
+
+ case eInputReaderInterrupt:
+ {
+ reader.SetIsDone (true);
+ if (!batch_mode)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ out_stream->PutCString("Regular expression command creations was cancelled.\n");
+ out_stream->Flush();
+ }
+ add_regex_cmd->InputReaderDidCancel ();
+ }
+ break;
+
+ case eInputReaderEndOfFile:
+ reader.SetIsDone (true);
+ break;
+
+ case eInputReaderDone:
+ add_regex_cmd->AddRegexCommandToInterpreter();
+ break;
+ }
+
+ return bytes_len;
+ }
+
+private:
+ std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_ap;
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'h':
+ m_help.assign (option_arg);
+ break;
+ case 's':
+ m_syntax.assign (option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_help.clear();
+ m_syntax.clear();
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ const char *
+ GetHelp ()
+ {
+ if (m_help.empty())
+ return NULL;
+ return m_help.c_str();
+ }
+ const char *
+ GetSyntax ()
+ {
+ if (m_syntax.empty())
+ return NULL;
+ return m_syntax.c_str();
+ }
+ // Instance variables to hold the values for command options.
+ protected:
+ std::string m_help;
+ std::string m_syntax;
+ };
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectCommandsAddRegex::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "help" , 'h', required_argument, NULL, 0, eArgTypeNone, "The help text to display for this command."},
+{ LLDB_OPT_SET_1, false, "syntax", 's', required_argument, NULL, 0, eArgTypeNone, "A syntax string showing the typical usage syntax."},
+{ 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone, NULL }
+};
+
+
+class CommandObjectPythonFunction : public CommandObjectRaw
+{
+private:
+ std::string m_function_name;
+ ScriptedCommandSynchronicity m_synchro;
+ bool m_fetched_help_long;
+
+public:
+
+ CommandObjectPythonFunction (CommandInterpreter &interpreter,
+ std::string name,
+ std::string funct,
+ ScriptedCommandSynchronicity synch) :
+ CommandObjectRaw (interpreter,
+ name.c_str(),
+ (std::string("Run Python function ") + funct).c_str(),
+ NULL),
+ m_function_name(funct),
+ m_synchro(synch),
+ m_fetched_help_long(false)
+ {
+ }
+
+ virtual
+ ~CommandObjectPythonFunction ()
+ {
+ }
+
+ virtual bool
+ IsRemovable () const
+ {
+ return true;
+ }
+
+ const std::string&
+ GetFunctionName ()
+ {
+ return m_function_name;
+ }
+
+ ScriptedCommandSynchronicity
+ GetSynchronicity ()
+ {
+ return m_synchro;
+ }
+
+ virtual const char *
+ GetHelpLong ()
+ {
+ if (!m_fetched_help_long)
+ {
+ ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter();
+ if (scripter)
+ {
+ std::string docstring;
+ m_fetched_help_long = scripter->GetDocumentationForItem(m_function_name.c_str(),docstring);
+ if (!docstring.empty())
+ SetHelpLong(docstring);
+ }
+ }
+ return CommandObjectRaw::GetHelpLong();
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *raw_command_line, CommandReturnObject &result)
+ {
+ ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter();
+
+ Error error;
+
+ result.SetStatus(eReturnStatusInvalid);
+
+ if (!scripter || scripter->RunScriptBasedCommand(m_function_name.c_str(),
+ raw_command_line,
+ m_synchro,
+ result,
+ error) == false)
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ }
+ else
+ {
+ // Don't change the status if the command already set it...
+ if (result.GetStatus() == eReturnStatusInvalid)
+ {
+ if (result.GetOutputData() == NULL || result.GetOutputData()[0] == '\0')
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ else
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsScriptImport
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsScriptImport : public CommandObjectParsed
+{
+public:
+ CommandObjectCommandsScriptImport (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command script import",
+ "Import a scripting module in LLDB.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentData cmd_arg;
+
+ // Define the first (and only) variant of this arg.
+ cmd_arg.arg_type = eArgTypeFilename;
+ cmd_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (cmd_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ }
+
+ ~CommandObjectCommandsScriptImport ()
+ {
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eDiskFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'r':
+ m_allow_reload = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_allow_reload = true;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_allow_reload;
+ };
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ if (m_interpreter.GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython)
+ {
+ result.AppendError ("only scripting language supported for module importing is currently Python");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendError ("'command script import' requires one argument");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ std::string path = command.GetArgumentAtIndex(0);
+ Error error;
+
+ const bool init_session = true;
+ // FIXME: this is necessary because CommandObject::CheckRequirements() assumes that
+ // commands won't ever be recursively invoked, but it's actually possible to craft
+ // a Python script that does other "command script imports" in __lldb_init_module
+ // the real fix is to have recursive commands possible with a CommandInvocation object
+ // separate from the CommandObject itself, so that recursive command invocations
+ // won't stomp on each other (wrt to execution contents, options, and more)
+ m_exe_ctx.Clear();
+ if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule(path.c_str(),
+ m_options.m_allow_reload,
+ init_session,
+ error))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("module importing failed: %s", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectCommandsScriptImport::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "allow-reload", 'r', no_argument, NULL, 0, eArgTypeNone, "Allow the script to be loaded even if it was already loaded before. This argument exists for backwards compatibility, but reloading is always allowed, whether you specify it or not."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsScriptAdd
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsScriptAdd : public CommandObjectParsed
+{
+public:
+ CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command script add",
+ "Add a scripted function as an LLDB command.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentData cmd_arg;
+
+ // Define the first (and only) variant of this arg.
+ cmd_arg.arg_type = eArgTypeCommandName;
+ cmd_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (cmd_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ }
+
+ ~CommandObjectCommandsScriptAdd ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'f':
+ m_funct_name = std::string(option_arg);
+ break;
+ case 's':
+ m_synchronous = (ScriptedCommandSynchronicity) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error);
+ if (!error.Success())
+ error.SetErrorStringWithFormat ("unrecognized value for synchronicity '%s'", option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_funct_name = "";
+ m_synchronous = eScriptedCommandSynchronicitySynchronous;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ std::string m_funct_name;
+ ScriptedCommandSynchronicity m_synchronous;
+ };
+
+private:
+ class PythonAliasReader : public InputReaderEZ
+ {
+ private:
+ CommandInterpreter& m_interpreter;
+ std::string m_cmd_name;
+ ScriptedCommandSynchronicity m_synchronous;
+ StringList m_user_input;
+ DISALLOW_COPY_AND_ASSIGN (PythonAliasReader);
+ public:
+ PythonAliasReader(Debugger& debugger,
+ CommandInterpreter& interpreter,
+ std::string cmd_name,
+ ScriptedCommandSynchronicity synch) :
+ InputReaderEZ(debugger),
+ m_interpreter(interpreter),
+ m_cmd_name(cmd_name),
+ m_synchronous(synch),
+ m_user_input()
+ {}
+
+ virtual
+ ~PythonAliasReader()
+ {
+ }
+
+ virtual void ActivateHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ if (!batch_mode)
+ {
+ out_stream->Printf ("%s\n", g_python_command_instructions);
+ if (data.reader.GetPrompt())
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+
+ virtual void ReactivateHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ if (data.reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+ virtual void GotTokenHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ if (data.bytes && data.bytes_len)
+ {
+ m_user_input.AppendString(data.bytes, data.bytes_len);
+ }
+ if (!data.reader.IsDone() && data.reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+ virtual void InterruptHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ data.reader.SetIsDone (true);
+ if (!batch_mode)
+ {
+ out_stream->Printf ("Warning: No script attached.\n");
+ out_stream->Flush();
+ }
+ }
+ virtual void EOFHandler(HandlerData& data)
+ {
+ data.reader.SetIsDone (true);
+ }
+ virtual void DoneHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+
+ ScriptInterpreter *interpreter = data.reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (!interpreter)
+ {
+ out_stream->Printf ("Script interpreter missing: no script attached.\n");
+ out_stream->Flush();
+ return;
+ }
+ std::string funct_name_str;
+ if (!interpreter->GenerateScriptAliasFunction (m_user_input,
+ funct_name_str))
+ {
+ out_stream->Printf ("Unable to create function: no script attached.\n");
+ out_stream->Flush();
+ return;
+ }
+ if (funct_name_str.empty())
+ {
+ out_stream->Printf ("Unable to obtain a function name: no script attached.\n");
+ out_stream->Flush();
+ return;
+ }
+ // everything should be fine now, let's add this alias
+
+ CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(m_interpreter,
+ m_cmd_name,
+ funct_name_str.c_str(),
+ m_synchronous));
+
+ if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, true))
+ {
+ out_stream->Printf ("Unable to add selected command: no script attached.\n");
+ out_stream->Flush();
+ return;
+ }
+ }
+ };
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ if (m_interpreter.GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython)
+ {
+ result.AppendError ("only scripting language supported for scripted commands is currently Python");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendError ("'command script add' requires one argument");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ std::string cmd_name = command.GetArgumentAtIndex(0);
+
+ if (m_options.m_funct_name.empty())
+ {
+ InputReaderSP reader_sp (new PythonAliasReader (m_interpreter.GetDebugger(),
+ m_interpreter,
+ cmd_name,
+ m_options.m_synchronous));
+
+ if (reader_sp)
+ {
+
+ InputReaderEZ::InitializationParameters ipr;
+
+ Error err (reader_sp->Initialize (ipr.SetBaton(NULL).SetPrompt(" ")));
+ if (err.Success())
+ {
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ CommandObjectSP new_cmd(new CommandObjectPythonFunction(m_interpreter,
+ cmd_name,
+ m_options.m_funct_name,
+ m_options.m_synchronous));
+ if (m_interpreter.AddUserCommand(cmd_name, new_cmd, true))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError("cannot add command");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+
+ return result.Succeeded();
+
+ }
+
+ CommandOptions m_options;
+};
+
+static OptionEnumValueElement g_script_synchro_type[] =
+{
+ { eScriptedCommandSynchronicitySynchronous, "synchronous", "Run synchronous"},
+ { eScriptedCommandSynchronicityAsynchronous, "asynchronous", "Run asynchronous"},
+ { eScriptedCommandSynchronicityCurrentValue, "current", "Do not alter current setting"},
+ { 0, NULL, NULL }
+};
+
+OptionDefinition
+CommandObjectCommandsScriptAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "function", 'f', required_argument, NULL, 0, eArgTypePythonFunction, "Name of the Python function to bind to this command name."},
+ { LLDB_OPT_SET_1, false, "synchronicity", 's', required_argument, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsScriptList
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsScriptList : public CommandObjectParsed
+{
+private:
+
+public:
+ CommandObjectCommandsScriptList(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command script list",
+ "List defined scripted commands.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectCommandsScriptList ()
+ {
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ m_interpreter.GetHelp(result,
+ CommandInterpreter::eCommandTypesUserDef);
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+
+ return true;
+
+
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsScriptClear
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsScriptClear : public CommandObjectParsed
+{
+private:
+
+public:
+ CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command script clear",
+ "Delete all scripted commands.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectCommandsScriptClear ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ m_interpreter.RemoveAllUser();
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+
+ return true;
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsScriptDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsScriptDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command script delete",
+ "Delete a scripted command.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentData cmd_arg;
+
+ // Define the first (and only) variant of this arg.
+ cmd_arg.arg_type = eArgTypeCommandName;
+ cmd_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (cmd_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ }
+
+ ~CommandObjectCommandsScriptDelete ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendError ("'command script delete' requires one argument");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char* cmd_name = command.GetArgumentAtIndex(0);
+
+ if (cmd_name && *cmd_name && m_interpreter.HasUserCommands() && m_interpreter.UserCommandExists(cmd_name))
+ {
+ m_interpreter.RemoveUser(cmd_name);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("command %s not found", cmd_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+
+ }
+};
+
+#pragma mark CommandObjectMultiwordCommandsScript
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordCommandsScript
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordCommandsScript (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "command script",
+ "A set of commands for managing or customizing script commands.",
+ "command script <subcommand> [<subcommand-options>]")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectCommandsScriptAdd (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectCommandsScriptDelete (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectCommandsScriptClear (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectCommandsScriptList (interpreter)));
+ LoadSubCommand ("import", CommandObjectSP (new CommandObjectCommandsScriptImport (interpreter)));
+ }
+
+ ~CommandObjectMultiwordCommandsScript ()
+ {
+ }
+
+};
+
+
+#pragma mark CommandObjectMultiwordCommands
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordCommands
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "command",
+ "A set of commands for managing or customizing the debugger commands.",
+ "command <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter)));
+ LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter)));
+ LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter)));
+ LoadSubCommand ("regex", CommandObjectSP (new CommandObjectCommandsAddRegex (interpreter)));
+ LoadSubCommand ("history", CommandObjectSP (new CommandObjectCommandsHistory (interpreter)));
+ LoadSubCommand ("script", CommandObjectSP (new CommandObjectMultiwordCommandsScript (interpreter)));
+}
+
+CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands ()
+{
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.h
new file mode 100644
index 0000000..8a56e8d
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.h
@@ -0,0 +1,40 @@
+//===-- CommandObjectCommands.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_CommandObjectCommands_h_
+#define liblldb_CommandObjectCommands_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Core/STLUtils.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordCommands
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordCommands : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordCommands (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordCommands ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectCommands_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.cpp
new file mode 100644
index 0000000..0d40fcd
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.cpp
@@ -0,0 +1,574 @@
+//===-- CommandObjectDisassemble.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 "CommandObjectDisassemble.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/SourceManager.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/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+
+#define DEFAULT_DISASM_BYTE_SIZE 32
+#define DEFAULT_DISASM_NUM_INS 4
+
+using namespace lldb;
+using namespace lldb_private;
+
+CommandObjectDisassemble::CommandOptions::CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter),
+ num_lines_context(0),
+ num_instructions (0),
+ func_name(),
+ current_function (false),
+ start_addr(),
+ end_addr (),
+ at_pc (false),
+ frame_line (false),
+ plugin_name (),
+ flavor_string(),
+ arch(),
+ some_location_specified (false),
+ symbol_containing_addr ()
+{
+ OptionParsingStarting();
+}
+
+CommandObjectDisassemble::CommandOptions::~CommandOptions ()
+{
+}
+
+Error
+CommandObjectDisassemble::CommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg)
+{
+ Error error;
+
+ const int short_option = m_getopt_table[option_idx].val;
+
+ bool success;
+
+ switch (short_option)
+ {
+ case 'm':
+ show_mixed = true;
+ break;
+
+ case 'C':
+ num_lines_context = Args::StringToUInt32(option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("invalid num context lines string: \"%s\"", option_arg);
+ break;
+
+ case 'c':
+ num_instructions = Args::StringToUInt32(option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("invalid num of instructions string: \"%s\"", option_arg);
+ break;
+
+ case 'b':
+ show_bytes = true;
+ break;
+
+ case 's':
+ {
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ start_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ if (start_addr != LLDB_INVALID_ADDRESS)
+ some_location_specified = true;
+ }
+ break;
+ case 'e':
+ {
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ end_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ if (end_addr != LLDB_INVALID_ADDRESS)
+ some_location_specified = true;
+ }
+ break;
+ case 'n':
+ func_name.assign (option_arg);
+ some_location_specified = true;
+ break;
+
+ case 'p':
+ at_pc = true;
+ some_location_specified = true;
+ break;
+
+ case 'l':
+ frame_line = true;
+ // Disassemble the current source line kind of implies showing mixed
+ // source code context.
+ show_mixed = true;
+ some_location_specified = true;
+ break;
+
+ case 'P':
+ plugin_name.assign (option_arg);
+ break;
+
+ case 'F':
+ {
+ Target *target = m_interpreter.GetExecutionContext().GetTargetPtr();
+ if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86
+ || target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86_64)
+ {
+ flavor_string.assign (option_arg);
+ }
+ else
+ error.SetErrorStringWithFormat("Disassembler flavors are currently only supported for x86 and x86_64 targets.");
+ break;
+ }
+ case 'r':
+ raw = true;
+ break;
+
+ case 'f':
+ current_function = true;
+ some_location_specified = true;
+ break;
+
+ case 'A':
+ if (!arch.SetTriple (option_arg, m_interpreter.GetPlatform (true).get()))
+ arch.SetTriple (option_arg);
+ break;
+
+ case 'a':
+ {
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ symbol_containing_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ if (symbol_containing_addr != LLDB_INVALID_ADDRESS)
+ {
+ some_location_specified = true;
+ }
+ }
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectDisassemble::CommandOptions::OptionParsingStarting ()
+{
+ show_mixed = false;
+ show_bytes = false;
+ num_lines_context = 0;
+ num_instructions = 0;
+ func_name.clear();
+ current_function = false;
+ at_pc = false;
+ frame_line = false;
+ start_addr = LLDB_INVALID_ADDRESS;
+ end_addr = LLDB_INVALID_ADDRESS;
+ symbol_containing_addr = LLDB_INVALID_ADDRESS;
+ raw = false;
+ plugin_name.clear();
+
+ Target *target = m_interpreter.GetExecutionContext().GetTargetPtr();
+
+ // This is a hack till we get the ability to specify features based on architecture. For now GetDisassemblyFlavor
+ // is really only valid for x86 (and for the llvm assembler plugin, but I'm papering over that since that is the
+ // only disassembler plugin we have...
+ if (target)
+ {
+ if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86
+ || target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86_64)
+ {
+ flavor_string.assign(target->GetDisassemblyFlavor());
+ }
+ else
+ flavor_string.assign ("default");
+
+ }
+ else
+ flavor_string.assign("default");
+
+ arch.Clear();
+ some_location_specified = false;
+}
+
+Error
+CommandObjectDisassemble::CommandOptions::OptionParsingFinished ()
+{
+ if (!some_location_specified)
+ current_function = true;
+ return Error();
+
+}
+
+const OptionDefinition*
+CommandObjectDisassemble::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+OptionDefinition
+CommandObjectDisassemble::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "bytes" , 'b', no_argument , NULL, 0, eArgTypeNone, "Show opcode bytes when disassembling."},
+{ LLDB_OPT_SET_ALL, false, "context" , 'C', required_argument , NULL, 0, eArgTypeNumLines, "Number of context lines of source to show."},
+{ LLDB_OPT_SET_ALL, false, "mixed" , 'm', no_argument , NULL, 0, eArgTypeNone, "Enable mixed source and assembly display."},
+{ LLDB_OPT_SET_ALL, false, "raw" , 'r', no_argument , NULL, 0, eArgTypeNone, "Print raw disassembly with no symbol information."},
+{ LLDB_OPT_SET_ALL, false, "plugin" , 'P', required_argument , NULL, 0, eArgTypePlugin, "Name of the disassembler plugin you want to use."},
+{ LLDB_OPT_SET_ALL, false, "flavor" , 'F', required_argument , NULL, 0, eArgTypeDisassemblyFlavor, "Name of the disassembly flavor you want to use. "
+ "Currently the only valid options are default, and for Intel"
+ " architectures, att and intel."},
+{ LLDB_OPT_SET_ALL, false, "arch" , 'A', required_argument , NULL, 0, eArgTypeArchitecture,"Specify the architecture to use from cross disassembly."},
+{ LLDB_OPT_SET_1 |
+ LLDB_OPT_SET_2 , true , "start-address", 's', required_argument , NULL, 0, eArgTypeAddressOrExpression,"Address at which to start disassembling."},
+{ LLDB_OPT_SET_1 , false, "end-address" , 'e', required_argument , NULL, 0, eArgTypeAddressOrExpression, "Address at which to end disassembling."},
+{ LLDB_OPT_SET_2 |
+ LLDB_OPT_SET_3 |
+ LLDB_OPT_SET_4 |
+ LLDB_OPT_SET_5 , false, "count" , 'c', required_argument , NULL, 0, eArgTypeNumLines, "Number of instructions to display."},
+{ LLDB_OPT_SET_3 , false, "name" , 'n', required_argument , NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
+ "Disassemble entire contents of the given function name."},
+{ LLDB_OPT_SET_4 , false, "frame" , 'f', no_argument , NULL, 0, eArgTypeNone, "Disassemble from the start of the current frame's function."},
+{ LLDB_OPT_SET_5 , false, "pc" , 'p', no_argument , NULL, 0, eArgTypeNone, "Disassemble around the current pc."},
+{ LLDB_OPT_SET_6 , false, "line" , 'l', no_argument , NULL, 0, eArgTypeNone, "Disassemble the current frame's current source line instructions if there debug line table information, else disasemble around the pc."},
+{ LLDB_OPT_SET_7 , false, "address" , 'a', required_argument , NULL, 0, eArgTypeAddressOrExpression, "Disassemble function containing this address."},
+{ 0 , false, NULL , 0, 0 , NULL, 0, eArgTypeNone, NULL }
+};
+
+
+
+//-------------------------------------------------------------------------
+// CommandObjectDisassemble
+//-------------------------------------------------------------------------
+
+CommandObjectDisassemble::CommandObjectDisassemble (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "disassemble",
+ "Disassemble bytes in the current function, or elsewhere in the executable program as specified by the user.",
+ "disassemble [<cmd-options>]"),
+ m_options (interpreter)
+{
+}
+
+CommandObjectDisassemble::~CommandObjectDisassemble()
+{
+}
+
+bool
+CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result)
+{
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ if (!m_options.arch.IsValid())
+ m_options.arch = target->GetArchitecture();
+
+ if (!m_options.arch.IsValid())
+ {
+ result.AppendError ("use the --arch option or set the target architecure to disassemble");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *plugin_name = m_options.GetPluginName ();
+ const char *flavor_string = m_options.GetFlavorString();
+
+ DisassemblerSP disassembler = Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name);
+
+ if (!disassembler)
+ {
+ if (plugin_name)
+ {
+ result.AppendErrorWithFormat ("Unable to find Disassembler plug-in named '%s' that supports the '%s' architecture.\n",
+ plugin_name,
+ m_options.arch.GetArchitectureName());
+ }
+ else
+ result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for the '%s' architecture.\n",
+ m_options.arch.GetArchitectureName());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else if (flavor_string != NULL && !disassembler->FlavorValidForArchSpec(m_options.arch, flavor_string))
+ result.AppendWarningWithFormat("invalid disassembler flavor \"%s\", using default.\n", flavor_string);
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+
+ if (command.GetArgumentCount() != 0)
+ {
+ result.AppendErrorWithFormat ("\"disassemble\" arguments are specified as options.\n");
+ GetOptions()->GenerateOptionUsage (result.GetErrorStream(), this);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.show_mixed && m_options.num_lines_context == 0)
+ m_options.num_lines_context = 1;
+
+ // Always show the PC in the disassembly
+ uint32_t options = Disassembler::eOptionMarkPCAddress;
+
+ // Mark the source line for the current PC only if we are doing mixed source and assembly
+ if (m_options.show_mixed)
+ options |= Disassembler::eOptionMarkPCSourceLine;
+
+ if (m_options.show_bytes)
+ options |= Disassembler::eOptionShowBytes;
+
+ if (m_options.raw)
+ options |= Disassembler::eOptionRawOuput;
+
+ if (!m_options.func_name.empty())
+ {
+ ConstString name(m_options.func_name.c_str());
+
+ if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
+ m_options.arch,
+ plugin_name,
+ flavor_string,
+ m_exe_ctx,
+ name,
+ NULL, // Module *
+ m_options.num_instructions,
+ m_options.show_mixed ? m_options.num_lines_context : 0,
+ options,
+ result.GetOutputStream()))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ AddressRange range;
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+ if (m_options.frame_line)
+ {
+ if (frame == NULL)
+ {
+ result.AppendError ("Cannot disassemble around the current line without a selected frame.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ LineEntry pc_line_entry (frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
+ if (pc_line_entry.IsValid())
+ {
+ range = pc_line_entry.range;
+ }
+ else
+ {
+ m_options.at_pc = true; // No line entry, so just disassemble around the current pc
+ m_options.show_mixed = false;
+ }
+ }
+ else if (m_options.current_function)
+ {
+ if (frame == NULL)
+ {
+ result.AppendError ("Cannot disassemble around the current function without a selected frame.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol;
+ if (symbol)
+ {
+ range.GetBaseAddress() = symbol->GetAddress();
+ range.SetByteSize(symbol->GetByteSize());
+ }
+ }
+
+ // Did the "m_options.frame_line" find a valid range already? If so
+ // skip the rest...
+ if (range.GetByteSize() == 0)
+ {
+ if (m_options.at_pc)
+ {
+ if (frame == NULL)
+ {
+ result.AppendError ("Cannot disassemble around the current PC without a selected frame.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ range.GetBaseAddress() = frame->GetFrameCodeAddress();
+ if (m_options.num_instructions == 0)
+ {
+ // Disassembling at the PC always disassembles some number of instructions (not the whole function).
+ m_options.num_instructions = DEFAULT_DISASM_NUM_INS;
+ }
+ }
+ else
+ {
+ range.GetBaseAddress().SetOffset (m_options.start_addr);
+ if (range.GetBaseAddress().IsValid())
+ {
+ if (m_options.end_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (m_options.end_addr <= m_options.start_addr)
+ {
+ result.AppendErrorWithFormat ("End address before start address.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ range.SetByteSize (m_options.end_addr - m_options.start_addr);
+ }
+ }
+ else
+ {
+ if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS
+ && target
+ && !target->GetSectionLoadList().IsEmpty())
+ {
+ bool failed = false;
+ Address symbol_containing_address;
+ if (target->GetSectionLoadList().ResolveLoadAddress (m_options.symbol_containing_addr, symbol_containing_address))
+ {
+ ModuleSP module_sp (symbol_containing_address.GetModule());
+ SymbolContext sc;
+ module_sp->ResolveSymbolContextForAddress (symbol_containing_address, eSymbolContextEverything, sc);
+ if (sc.function || sc.symbol)
+ {
+ sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range);
+ }
+ else
+ {
+ failed = true;
+ }
+ }
+ else
+ {
+ failed = true;
+ }
+ if (failed)
+ {
+ result.AppendErrorWithFormat ("Could not find function bounds for address 0x%" PRIx64 "\n", m_options.symbol_containing_addr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ if (m_options.num_instructions != 0)
+ {
+ if (!range.GetBaseAddress().IsValid())
+ {
+ // The default action is to disassemble the current frame function.
+ if (frame)
+ {
+ SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
+ if (sc.function)
+ range.GetBaseAddress() = sc.function->GetAddressRange().GetBaseAddress();
+ else if (sc.symbol && sc.symbol->ValueIsAddress())
+ range.GetBaseAddress() = sc.symbol->GetAddress();
+ else
+ range.GetBaseAddress() = frame->GetFrameCodeAddress();
+ }
+
+ if (!range.GetBaseAddress().IsValid())
+ {
+ result.AppendError ("invalid frame");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
+ m_options.arch,
+ plugin_name,
+ flavor_string,
+ m_exe_ctx,
+ range.GetBaseAddress(),
+ m_options.num_instructions,
+ m_options.show_mixed ? m_options.num_lines_context : 0,
+ options,
+ result.GetOutputStream()))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ if (!range.GetBaseAddress().IsValid())
+ {
+ // The default action is to disassemble the current frame function.
+ if (frame)
+ {
+ SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
+ if (sc.function)
+ range = sc.function->GetAddressRange();
+ else if (sc.symbol && sc.symbol->ValueIsAddress())
+ {
+ range.GetBaseAddress() = sc.symbol->GetAddress();
+ range.SetByteSize (sc.symbol->GetByteSize());
+ }
+ else
+ range.GetBaseAddress() = frame->GetFrameCodeAddress();
+ }
+ else
+ {
+ result.AppendError ("invalid frame");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ if (range.GetByteSize() == 0)
+ range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);
+
+ if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
+ m_options.arch,
+ plugin_name,
+ flavor_string,
+ m_exe_ctx,
+ range,
+ m_options.num_instructions,
+ m_options.show_mixed ? m_options.num_lines_context : 0,
+ options,
+ result.GetOutputStream()))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+
+ return result.Succeeded();
+}
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.h
new file mode 100644
index 0000000..7a75098
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.h
@@ -0,0 +1,110 @@
+//===-- CommandObjectDisassemble.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_CommandObjectDisassemble_h_
+#define liblldb_CommandObjectDisassemble_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/Options.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectDisassemble
+//-------------------------------------------------------------------------
+
+class CommandObjectDisassemble : public CommandObjectParsed
+{
+public:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandOptions ();
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg);
+
+ void
+ OptionParsingStarting ();
+
+ const OptionDefinition*
+ GetDefinitions ();
+
+ const char *
+ GetPluginName ()
+ {
+ if (plugin_name.empty())
+ return NULL;
+ return plugin_name.c_str();
+ }
+
+ const char *
+ GetFlavorString ()
+ {
+ if (flavor_string.empty() || flavor_string == "default")
+ return NULL;
+ return flavor_string.c_str();
+ }
+
+ virtual Error
+ OptionParsingFinished ();
+
+ bool show_mixed; // Show mixed source/assembly
+ bool show_bytes;
+ uint32_t num_lines_context;
+ uint32_t num_instructions;
+ bool raw;
+ std::string func_name;
+ bool current_function;
+ lldb::addr_t start_addr;
+ lldb::addr_t end_addr;
+ bool at_pc;
+ bool frame_line;
+ std::string plugin_name;
+ std::string flavor_string;
+ ArchSpec arch;
+ bool some_location_specified; // If no location was specified, we'll select "at_pc". This should be set
+ // in SetOptionValue if anything the selects a location is set.
+ lldb::addr_t symbol_containing_addr;
+ static OptionDefinition g_option_table[];
+ };
+
+ CommandObjectDisassemble (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectDisassemble ();
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result);
+
+ CommandOptions m_options;
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectDisassemble_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.cpp
new file mode 100644
index 0000000..da472d1
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.cpp
@@ -0,0 +1,505 @@
+//===-- CommandObjectExpression.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 "CommandObjectExpression.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+CommandObjectExpression::CommandOptions::CommandOptions () :
+ OptionGroup()
+{
+}
+
+
+CommandObjectExpression::CommandOptions::~CommandOptions ()
+{
+}
+
+OptionDefinition
+CommandObjectExpression::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "all-threads", 'a', required_argument, NULL, 0, eArgTypeBoolean, "Should we run all threads if the execution doesn't complete on one thread."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "ignore-breakpoints", 'i', required_argument, NULL, 0, eArgTypeBoolean, "Ignore breakpoint hits while running expressions"},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout", 't', required_argument, NULL, 0, eArgTypeUnsignedInteger, "Timeout value (in microseconds) for running the expression."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error", 'u', required_argument, NULL, 0, eArgTypeBoolean, "Clean up program state if the expression causes a crash, or raises a signal. Note, unlike gdb hitting a breakpoint is controlled by another option (-i)."},
+};
+
+
+uint32_t
+CommandObjectExpression::CommandOptions::GetNumDefinitions ()
+{
+ return sizeof(g_option_table)/sizeof(OptionDefinition);
+}
+
+Error
+CommandObjectExpression::CommandOptions::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 'l':
+ //if (language.SetLanguageFromCString (option_arg) == false)
+ //{
+ // error.SetErrorStringWithFormat("invalid language option argument '%s'", option_arg);
+ //}
+ //break;
+
+ case 'a':
+ {
+ bool success;
+ bool result;
+ result = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid all-threads value setting: \"%s\"", option_arg);
+ else
+ try_all_threads = result;
+ }
+ break;
+
+ case 'i':
+ {
+ bool success;
+ bool tmp_value = Args::StringToBoolean(option_arg, true, &success);
+ if (success)
+ ignore_breakpoints = tmp_value;
+ else
+ error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);
+ break;
+ }
+ case 't':
+ {
+ bool success;
+ uint32_t result;
+ result = Args::StringToUInt32(option_arg, 0, 0, &success);
+ if (success)
+ timeout = result;
+ else
+ error.SetErrorStringWithFormat ("invalid timeout setting \"%s\"", option_arg);
+ }
+ break;
+
+ case 'u':
+ {
+ bool success;
+ bool tmp_value = Args::StringToBoolean(option_arg, true, &success);
+ if (success)
+ unwind_on_error = tmp_value;
+ else
+ error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);
+ break;
+ }
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ Process *process = interpreter.GetExecutionContext().GetProcessPtr();
+ if (process != NULL)
+ {
+ ignore_breakpoints = process->GetIgnoreBreakpointsInExpressions();
+ unwind_on_error = process->GetUnwindOnErrorInExpressions();
+ }
+ else
+ {
+ ignore_breakpoints = false;
+ unwind_on_error = true;
+ }
+
+ show_summary = true;
+ try_all_threads = true;
+ timeout = 0;
+}
+
+const OptionDefinition*
+CommandObjectExpression::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "expression",
+ "Evaluate a C/ObjC/C++ expression in the current program context, using user defined variables and variables currently in scope.",
+ NULL,
+ eFlagProcessMustBePaused | eFlagTryTargetAPILock),
+ m_option_group (interpreter),
+ m_format_options (eFormatDefault),
+ m_command_options (),
+ m_expr_line_count (0),
+ m_expr_lines ()
+{
+ SetHelpLong(
+"Timeouts:\n\
+ If the expression can be evaluated statically (without runnning code) then it will be.\n\
+ Otherwise, by default the expression will run on the current thread with a short timeout:\n\
+ currently .25 seconds. If it doesn't return in that time, the evaluation will be interrupted\n\
+ and resumed with all threads running. You can use the -a option to disable retrying on all\n\
+ threads. You can use the -t option to set a shorter timeout.\n\
+\n\
+User defined variables:\n\
+ You can define your own variables for convenience or to be used in subsequent expressions.\n\
+ You define them the same way you would define variables in C. If the first character of \n\
+ your user defined variable is a $, then the variable's value will be available in future\n\
+ expressions, otherwise it will just be available in the current expression.\n\
+\n\
+Examples: \n\
+\n\
+ expr my_struct->a = my_array[3] \n\
+ expr -f bin -- (index * 8) + 5 \n\
+ expr unsigned int $foo = 5\n\
+ expr char c[] = \"foo\"; c[0]\n");
+
+ CommandArgumentEntry arg;
+ CommandArgumentData expression_arg;
+
+ // Define the first (and only) variant of this arg.
+ expression_arg.arg_type = eArgTypeExpression;
+ expression_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (expression_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+ // Add the "--format" and "--gdb-format"
+ m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_command_options);
+ m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
+ m_option_group.Finalize();
+}
+
+CommandObjectExpression::~CommandObjectExpression ()
+{
+}
+
+Options *
+CommandObjectExpression::GetOptions ()
+{
+ return &m_option_group;
+}
+
+size_t
+CommandObjectExpression::MultiLineExpressionCallback
+(
+ void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len
+)
+{
+ CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton;
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ if (!batch_mode)
+ {
+ StreamSP async_strm_sp(reader.GetDebugger().GetAsyncOutputStream());
+ if (async_strm_sp)
+ {
+ async_strm_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n");
+ async_strm_sp->Flush();
+ }
+ }
+ // Fall through
+ case eInputReaderReactivate:
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderGotToken:
+ ++cmd_object_expr->m_expr_line_count;
+ if (bytes && bytes_len)
+ {
+ cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1);
+ }
+
+ if (bytes_len == 0)
+ reader.SetIsDone(true);
+ break;
+
+ case eInputReaderInterrupt:
+ cmd_object_expr->m_expr_lines.clear();
+ reader.SetIsDone (true);
+ if (!batch_mode)
+ {
+ StreamSP async_strm_sp (reader.GetDebugger().GetAsyncOutputStream());
+ if (async_strm_sp)
+ {
+ async_strm_sp->PutCString("Expression evaluation cancelled.\n");
+ async_strm_sp->Flush();
+ }
+ }
+ break;
+
+ case eInputReaderEndOfFile:
+ reader.SetIsDone (true);
+ break;
+
+ case eInputReaderDone:
+ if (cmd_object_expr->m_expr_lines.size() > 0)
+ {
+ StreamSP output_stream = reader.GetDebugger().GetAsyncOutputStream();
+ StreamSP error_stream = reader.GetDebugger().GetAsyncErrorStream();
+ cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(),
+ output_stream.get(),
+ error_stream.get());
+ output_stream->Flush();
+ error_stream->Flush();
+ }
+ break;
+ }
+
+ return bytes_len;
+}
+
+bool
+CommandObjectExpression::EvaluateExpression
+(
+ const char *expr,
+ Stream *output_stream,
+ Stream *error_stream,
+ CommandReturnObject *result
+)
+{
+ // Don't use m_exe_ctx as this might be called asynchronously
+ // after the command object DoExecute has finished when doing
+ // multi-line expression that use an input reader...
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+
+ Target *target = exe_ctx.GetTargetPtr();
+
+ if (!target)
+ target = Host::GetDummyTarget(m_interpreter.GetDebugger()).get();
+
+ if (target)
+ {
+ lldb::ValueObjectSP result_valobj_sp;
+
+ ExecutionResults exe_results;
+
+ bool keep_in_memory = true;
+
+ EvaluateExpressionOptions options;
+ options.SetCoerceToId(m_varobj_options.use_objc)
+ .SetUnwindOnError(m_command_options.unwind_on_error)
+ .SetIgnoreBreakpoints (m_command_options.ignore_breakpoints)
+ .SetKeepInMemory(keep_in_memory)
+ .SetUseDynamic(m_varobj_options.use_dynamic)
+ .SetRunOthers(m_command_options.try_all_threads)
+ .SetTimeoutUsec(m_command_options.timeout);
+
+ exe_results = target->EvaluateExpression (expr,
+ exe_ctx.GetFramePtr(),
+ result_valobj_sp,
+ options);
+
+ if (result_valobj_sp)
+ {
+ Format format = m_format_options.GetFormat();
+
+ if (result_valobj_sp->GetError().Success())
+ {
+ if (format != eFormatVoid)
+ {
+ if (format != eFormatDefault)
+ result_valobj_sp->SetFormat (format);
+
+ ValueObject::DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(true,format));
+
+ ValueObject::DumpValueObject (*(output_stream),
+ result_valobj_sp.get(), // Variable object to dump
+ options);
+ if (result)
+ result->SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ }
+ else
+ {
+ if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult)
+ {
+ if (format != eFormatVoid && m_interpreter.GetDebugger().GetNotifyVoid())
+ {
+ error_stream->PutCString("(void)\n");
+ }
+
+ if (result)
+ result->SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ const char *error_cstr = result_valobj_sp->GetError().AsCString();
+ if (error_cstr && error_cstr[0])
+ {
+ const size_t error_cstr_len = strlen (error_cstr);
+ const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
+ if (strstr(error_cstr, "error:") != error_cstr)
+ error_stream->PutCString ("error: ");
+ error_stream->Write(error_cstr, error_cstr_len);
+ if (!ends_with_newline)
+ error_stream->EOL();
+ }
+ else
+ {
+ error_stream->PutCString ("error: unknown error\n");
+ }
+
+ if (result)
+ result->SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ }
+ else
+ {
+ error_stream->Printf ("error: invalid execution context for expression\n");
+ return false;
+ }
+
+ return true;
+}
+
+bool
+CommandObjectExpression::DoExecute
+(
+ const char *command,
+ CommandReturnObject &result
+)
+{
+ m_option_group.NotifyOptionParsingStarting();
+
+ const char * expr = NULL;
+
+ if (command[0] == '\0')
+ {
+ m_expr_lines.clear();
+ m_expr_line_count = 0;
+
+ InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
+ if (reader_sp)
+ {
+ Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
+ this, // baton
+ eInputReaderGranularityLine, // token size, to pass to callback function
+ NULL, // end token
+ NULL, // prompt
+ true)); // echo input
+ if (err.Success())
+ {
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ if (command[0] == '-')
+ {
+ // We have some options and these options MUST end with --.
+ const char *end_options = NULL;
+ const char *s = command;
+ while (s && s[0])
+ {
+ end_options = ::strstr (s, "--");
+ if (end_options)
+ {
+ end_options += 2; // Get past the "--"
+ if (::isspace (end_options[0]))
+ {
+ expr = end_options;
+ while (::isspace (*expr))
+ ++expr;
+ break;
+ }
+ }
+ s = end_options;
+ }
+
+ if (end_options)
+ {
+ Args args (command, end_options - command);
+ if (!ParseOptions (args, result))
+ return false;
+
+ Error error (m_option_group.NotifyOptionParsingFinished());
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+
+ if (expr == NULL)
+ expr = command;
+
+ if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result))
+ return true;
+
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.h
new file mode 100644
index 0000000..3964f2d
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.h
@@ -0,0 +1,99 @@
+//===-- CommandObjectExpression.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_CommandObjectExpression_h_
+#define liblldb_CommandObjectExpression_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
+#include "lldb/Target/ExecutionContext.h"
+
+namespace lldb_private {
+
+class CommandObjectExpression : public CommandObjectRaw
+{
+public:
+
+ class CommandOptions : public OptionGroup
+ {
+ public:
+
+ CommandOptions ();
+
+ virtual
+ ~CommandOptions ();
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ virtual const OptionDefinition*
+ GetDefinitions ();
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+ bool unwind_on_error;
+ bool ignore_breakpoints;
+ bool show_types;
+ bool show_summary;
+ uint32_t timeout;
+ bool try_all_threads;
+ };
+
+ CommandObjectExpression (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectExpression ();
+
+ virtual
+ Options *
+ GetOptions ();
+
+protected:
+ virtual bool
+ DoExecute (const char *command,
+ CommandReturnObject &result);
+
+ static size_t
+ MultiLineExpressionCallback (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+ bool
+ EvaluateExpression (const char *expr,
+ Stream *output_stream,
+ Stream *error_stream,
+ CommandReturnObject *result = NULL);
+
+ OptionGroupOptions m_option_group;
+ OptionGroupFormat m_format_options;
+ OptionGroupValueObjectDisplay m_varobj_options;
+ CommandOptions m_command_options;
+ uint32_t m_expr_line_count;
+ std::string m_expr_lines; // Multi-line expression support
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectExpression_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.cpp
new file mode 100644
index 0000000..aace3a6
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.cpp
@@ -0,0 +1,624 @@
+//===-- CommandObjectFrame.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 "CommandObjectFrame.h"
+
+// C Includes
+// C++ Includes
+#include <string>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
+#include "lldb/Interpreter/OptionGroupVariable.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#pragma mark CommandObjectFrameInfo
+
+//-------------------------------------------------------------------------
+// CommandObjectFrameInfo
+//-------------------------------------------------------------------------
+
+class CommandObjectFrameInfo : public CommandObjectParsed
+{
+public:
+
+ CommandObjectFrameInfo (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "frame info",
+ "List information about the currently selected frame in the current thread.",
+ "frame info",
+ eFlagRequiresFrame |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused )
+ {
+ }
+
+ ~CommandObjectFrameInfo ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat (&result.GetOutputStream());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+};
+
+#pragma mark CommandObjectFrameSelect
+
+//-------------------------------------------------------------------------
+// CommandObjectFrameSelect
+//-------------------------------------------------------------------------
+
+class CommandObjectFrameSelect : public CommandObjectParsed
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ OptionParsingStarting ();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ bool success = false;
+ const int short_option = m_getopt_table[option_idx].val;
+ switch (short_option)
+ {
+ case 'r':
+ relative_frame_offset = Args::StringToSInt32 (option_arg, INT32_MIN, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("invalid frame offset argument '%s'", option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("invalid short option character '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ relative_frame_offset = INT32_MIN;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+ int32_t relative_frame_offset;
+ };
+
+ CommandObjectFrameSelect (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "frame select",
+ "Select a frame by index from within the current thread and make it the current frame.",
+ NULL,
+ eFlagRequiresThread |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData index_arg;
+
+ // Define the first (and only) variant of this arg.
+ index_arg.arg_type = eArgTypeFrameIndex;
+ index_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (index_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectFrameSelect ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ // No need to check "thread" for validity as eFlagRequiresThread ensures it is valid
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+
+ uint32_t frame_idx = UINT32_MAX;
+ if (m_options.relative_frame_offset != INT32_MIN)
+ {
+ // The one and only argument is a signed relative frame index
+ frame_idx = thread->GetSelectedFrameIndex ();
+ if (frame_idx == UINT32_MAX)
+ frame_idx = 0;
+
+ if (m_options.relative_frame_offset < 0)
+ {
+ if (frame_idx >= -m_options.relative_frame_offset)
+ frame_idx += m_options.relative_frame_offset;
+ else
+ {
+ if (frame_idx == 0)
+ {
+ //If you are already at the bottom of the stack, then just warn and don't reset the frame.
+ result.AppendError("Already at the bottom of the stack");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else
+ frame_idx = 0;
+ }
+ }
+ else if (m_options.relative_frame_offset > 0)
+ {
+ // I don't want "up 20" where "20" takes you past the top of the stack to produce
+ // an error, but rather to just go to the top. So I have to count the stack here...
+ const uint32_t num_frames = thread->GetStackFrameCount();
+ if (num_frames - frame_idx > m_options.relative_frame_offset)
+ frame_idx += m_options.relative_frame_offset;
+ else
+ {
+ if (frame_idx == num_frames - 1)
+ {
+ //If we are already at the top of the stack, just warn and don't reset the frame.
+ result.AppendError("Already at the top of the stack");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else
+ frame_idx = num_frames - 1;
+ }
+ }
+ }
+ else
+ {
+ if (command.GetArgumentCount() == 1)
+ {
+ const char *frame_idx_cstr = command.GetArgumentAtIndex(0);
+ frame_idx = Args::StringToUInt32 (frame_idx_cstr, UINT32_MAX, 0);
+ }
+ else if (command.GetArgumentCount() == 0)
+ {
+ frame_idx = thread->GetSelectedFrameIndex ();
+ if (frame_idx == UINT32_MAX)
+ {
+ frame_idx = 0;
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid arguments.\n");
+ m_options.GenerateOptionUsage (result.GetErrorStream(), this);
+ }
+ }
+
+ bool success = thread->SetSelectedFrameByIndexNoisily (frame_idx, result.GetOutputStream());
+ if (success)
+ {
+ m_exe_ctx.SetFrameSP(thread->GetSelectedFrame ());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx);
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+protected:
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectFrameSelect::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "relative", 'r', required_argument, NULL, 0, eArgTypeOffset, "A relative frame index offset from the current frame index."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#pragma mark CommandObjectFrameVariable
+//----------------------------------------------------------------------
+// List images with associated information
+//----------------------------------------------------------------------
+class CommandObjectFrameVariable : public CommandObjectParsed
+{
+public:
+
+ CommandObjectFrameVariable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "frame variable",
+ "Show frame variables. All argument and local variables "
+ "that are in scope will be shown when no arguments are given. "
+ "If any arguments are specified, they can be names of "
+ "argument, local, file static and file global variables. "
+ "Children of aggregate variables can be specified such as "
+ "'var->child.x'.",
+ NULL,
+ eFlagRequiresFrame |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused |
+ eFlagRequiresProcess),
+ m_option_group (interpreter),
+ m_option_variable(true), // Include the frame specific options by passing "true"
+ m_option_format (eFormatDefault),
+ m_varobj_options()
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData var_name_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeVarName;
+ var_name_arg.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (var_name_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+ m_option_group.Append (&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_option_format, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectFrameVariable ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ // Arguments are the standard source file completer.
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eVariablePathCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ // No need to check "frame" for validity as eFlagRequiresFrame ensures it is valid
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+
+ Stream &s = result.GetOutputStream();
+
+ bool get_file_globals = true;
+
+ // Be careful about the stack frame, if any summary formatter runs code, it might clear the StackFrameList
+ // for the thread. So hold onto a shared pointer to the frame so it stays alive.
+
+ VariableList *variable_list = frame->GetVariableList (get_file_globals);
+
+ VariableSP var_sp;
+ ValueObjectSP valobj_sp;
+
+ const char *name_cstr = NULL;
+ size_t idx;
+
+ TypeSummaryImplSP summary_format_sp;
+ if (!m_option_variable.summary.IsCurrentValueEmpty())
+ DataVisualization::NamedSummaryFormats::GetSummaryFormat(ConstString(m_option_variable.summary.GetCurrentValue()), summary_format_sp);
+ else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
+ summary_format_sp.reset(new StringSummaryFormat(TypeSummaryImpl::Flags(),m_option_variable.summary_string.GetCurrentValue()));
+
+ ValueObject::DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(false,eFormatDefault,summary_format_sp));
+
+ if (variable_list)
+ {
+ const Format format = m_option_format.GetFormat();
+ options.SetFormat(format);
+
+ if (command.GetArgumentCount() > 0)
+ {
+ VariableList regex_var_list;
+
+ // If we have any args to the variable command, we will make
+ // variable objects from them...
+ for (idx = 0; (name_cstr = command.GetArgumentAtIndex(idx)) != NULL; ++idx)
+ {
+ if (m_option_variable.use_regex)
+ {
+ const size_t regex_start_index = regex_var_list.GetSize();
+ RegularExpression regex (name_cstr);
+ if (regex.Compile(name_cstr))
+ {
+ size_t num_matches = 0;
+ const size_t num_new_regex_vars = variable_list->AppendVariablesIfUnique(regex,
+ regex_var_list,
+ num_matches);
+ if (num_new_regex_vars > 0)
+ {
+ for (size_t regex_idx = regex_start_index, end_index = regex_var_list.GetSize();
+ regex_idx < end_index;
+ ++regex_idx)
+ {
+ var_sp = regex_var_list.GetVariableAtIndex (regex_idx);
+ if (var_sp)
+ {
+ valobj_sp = frame->GetValueObjectForFrameVariable (var_sp, m_varobj_options.use_dynamic);
+ if (valobj_sp)
+ {
+// if (format != eFormatDefault)
+// valobj_sp->SetFormat (format);
+
+ if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile())
+ {
+ bool show_fullpaths = false;
+ bool show_module = true;
+ if (var_sp->DumpDeclaration(&s, show_fullpaths, show_module))
+ s.PutCString (": ");
+ }
+ ValueObject::DumpValueObject (result.GetOutputStream(),
+ valobj_sp.get(),
+ options);
+ }
+ }
+ }
+ }
+ else if (num_matches == 0)
+ {
+ result.GetErrorStream().Printf ("error: no variables matched the regular expression '%s'.\n", name_cstr);
+ }
+ }
+ else
+ {
+ char regex_error[1024];
+ if (regex.GetErrorAsCString(regex_error, sizeof(regex_error)))
+ result.GetErrorStream().Printf ("error: %s\n", regex_error);
+ else
+ result.GetErrorStream().Printf ("error: unkown regex error when compiling '%s'\n", name_cstr);
+ }
+ }
+ else // No regex, either exact variable names or variable expressions.
+ {
+ Error error;
+ uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember |
+ StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
+ lldb::VariableSP var_sp;
+ valobj_sp = frame->GetValueForVariableExpressionPath (name_cstr,
+ m_varobj_options.use_dynamic,
+ expr_path_options,
+ var_sp,
+ error);
+ if (valobj_sp)
+ {
+// if (format != eFormatDefault)
+// valobj_sp->SetFormat (format);
+ if (m_option_variable.show_decl && var_sp && var_sp->GetDeclaration ().GetFile())
+ {
+ var_sp->GetDeclaration ().DumpStopContext (&s, false);
+ s.PutCString (": ");
+ }
+
+ options.SetFormat(format);
+
+ Stream &output_stream = result.GetOutputStream();
+ options.SetRootValueObjectName(valobj_sp->GetParent() ? name_cstr : NULL);
+ ValueObject::DumpValueObject (output_stream,
+ valobj_sp.get(),
+ options);
+ }
+ else
+ {
+ const char *error_cstr = error.AsCString(NULL);
+ if (error_cstr)
+ result.GetErrorStream().Printf("error: %s\n", error_cstr);
+ else
+ result.GetErrorStream().Printf ("error: unable to find any variable expression path that matches '%s'\n", name_cstr);
+ }
+ }
+ }
+ }
+ else // No command arg specified. Use variable_list, instead.
+ {
+ const size_t num_variables = variable_list->GetSize();
+ if (num_variables > 0)
+ {
+ for (size_t i=0; i<num_variables; i++)
+ {
+ var_sp = variable_list->GetVariableAtIndex(i);
+ bool dump_variable = true;
+ switch (var_sp->GetScope())
+ {
+ case eValueTypeVariableGlobal:
+ dump_variable = m_option_variable.show_globals;
+ if (dump_variable && m_option_variable.show_scope)
+ s.PutCString("GLOBAL: ");
+ break;
+
+ case eValueTypeVariableStatic:
+ dump_variable = m_option_variable.show_globals;
+ if (dump_variable && m_option_variable.show_scope)
+ s.PutCString("STATIC: ");
+ break;
+
+ case eValueTypeVariableArgument:
+ dump_variable = m_option_variable.show_args;
+ if (dump_variable && m_option_variable.show_scope)
+ s.PutCString(" ARG: ");
+ break;
+
+ case eValueTypeVariableLocal:
+ dump_variable = m_option_variable.show_locals;
+ if (dump_variable && m_option_variable.show_scope)
+ s.PutCString(" LOCAL: ");
+ break;
+
+ default:
+ break;
+ }
+
+ if (dump_variable)
+ {
+ // Use the variable object code to make sure we are
+ // using the same APIs as the the public API will be
+ // using...
+ valobj_sp = frame->GetValueObjectForFrameVariable (var_sp,
+ m_varobj_options.use_dynamic);
+ if (valobj_sp)
+ {
+// if (format != eFormatDefault)
+// valobj_sp->SetFormat (format);
+
+ // When dumping all variables, don't print any variables
+ // that are not in scope to avoid extra unneeded output
+ if (valobj_sp->IsInScope ())
+ {
+ if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile())
+ {
+ var_sp->GetDeclaration ().DumpStopContext (&s, false);
+ s.PutCString (": ");
+ }
+
+ options.SetFormat(format);
+ options.SetRootValueObjectName(name_cstr);
+ ValueObject::DumpValueObject (result.GetOutputStream(),
+ valobj_sp.get(),
+ options);
+ }
+ }
+ }
+ }
+ }
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+
+ if (m_interpreter.TruncationWarningNecessary())
+ {
+ result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
+ m_cmd_name.c_str());
+ m_interpreter.TruncationWarningGiven();
+ }
+
+ return result.Succeeded();
+ }
+protected:
+
+ OptionGroupOptions m_option_group;
+ OptionGroupVariable m_option_variable;
+ OptionGroupFormat m_option_format;
+ OptionGroupValueObjectDisplay m_varobj_options;
+};
+
+
+#pragma mark CommandObjectMultiwordFrame
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordFrame
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordFrame::CommandObjectMultiwordFrame (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "frame",
+ "A set of commands for operating on the current thread's frames.",
+ "frame <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand ("info", CommandObjectSP (new CommandObjectFrameInfo (interpreter)));
+ LoadSubCommand ("select", CommandObjectSP (new CommandObjectFrameSelect (interpreter)));
+ LoadSubCommand ("variable", CommandObjectSP (new CommandObjectFrameVariable (interpreter)));
+}
+
+CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame ()
+{
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.h
new file mode 100644
index 0000000..ea7c808
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.h
@@ -0,0 +1,40 @@
+//===-- CommandObjectFrame.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_CommandObjectFrame_h_
+#define liblldb_CommandObjectFrame_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordFrame
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordFrame : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordFrame (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordFrame ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectFrame_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectHelp.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectHelp.cpp
new file mode 100644
index 0000000..d2c97f9
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectHelp.cpp
@@ -0,0 +1,249 @@
+//===-- CommandObjectHelp.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 "CommandObjectHelp.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectHelp
+//-------------------------------------------------------------------------
+
+CommandObjectHelp::CommandObjectHelp (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "help",
+ "Show a list of all debugger commands, or give details about specific commands.",
+ "help [<cmd-name>]"), m_options (interpreter)
+{
+ CommandArgumentEntry arg;
+ CommandArgumentData command_arg;
+
+ // Define the first (and only) variant of this arg.
+ command_arg.arg_type = eArgTypeCommandName;
+ command_arg.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (command_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+}
+
+CommandObjectHelp::~CommandObjectHelp()
+{
+}
+
+OptionDefinition
+CommandObjectHelp::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "show-aliases", 'a', no_argument, NULL, 0, eArgTypeNone, "Show aliases in the command list."},
+ { LLDB_OPT_SET_ALL, false, "hide-user-commands", 'u', no_argument, NULL, 0, eArgTypeNone, "Hide user-defined commands from the list."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+bool
+CommandObjectHelp::DoExecute (Args& command, CommandReturnObject &result)
+{
+ CommandObject::CommandMap::iterator pos;
+ CommandObject *cmd_obj;
+ const size_t argc = command.GetArgumentCount ();
+
+ // 'help' doesn't take any arguments, other than command names. If argc is 0, we show the user
+ // all commands (aliases and user commands if asked for). Otherwise every argument must be the name of a command or a sub-command.
+ if (argc == 0)
+ {
+ uint32_t cmd_types = CommandInterpreter::eCommandTypesBuiltin;
+ if (m_options.m_show_aliases)
+ cmd_types |= CommandInterpreter::eCommandTypesAliases;
+ if (m_options.m_show_user_defined)
+ cmd_types |= CommandInterpreter::eCommandTypesUserDef;
+
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ m_interpreter.GetHelp (result, cmd_types); // General help
+ }
+ else
+ {
+ // Get command object for the first command argument. Only search built-in command dictionary.
+ StringList matches;
+ cmd_obj = m_interpreter.GetCommandObject (command.GetArgumentAtIndex (0), &matches);
+ bool is_alias_command = m_interpreter.AliasExists (command.GetArgumentAtIndex (0));
+ std::string alias_name = command.GetArgumentAtIndex(0);
+
+ if (cmd_obj != NULL)
+ {
+ StringList matches;
+ bool all_okay = true;
+ CommandObject *sub_cmd_obj = cmd_obj;
+ // Loop down through sub_command dictionaries until we find the command object that corresponds
+ // to the help command entered.
+ for (size_t i = 1; i < argc && all_okay; ++i)
+ {
+ std::string sub_command = command.GetArgumentAtIndex(i);
+ matches.Clear();
+ if (! sub_cmd_obj->IsMultiwordObject ())
+ {
+ all_okay = false;
+ }
+ else
+ {
+ CommandObject *found_cmd;
+ found_cmd = sub_cmd_obj->GetSubcommandObject(sub_command.c_str(), &matches);
+ if (found_cmd == NULL)
+ all_okay = false;
+ else if (matches.GetSize() > 1)
+ all_okay = false;
+ else
+ sub_cmd_obj = found_cmd;
+ }
+ }
+
+ if (!all_okay || (sub_cmd_obj == NULL))
+ {
+ std::string cmd_string;
+ command.GetCommandString (cmd_string);
+ if (matches.GetSize() >= 2)
+ {
+ StreamString s;
+ s.Printf ("ambiguous command %s", cmd_string.c_str());
+ size_t num_matches = matches.GetSize();
+ for (size_t match_idx = 0; match_idx < num_matches; match_idx++)
+ {
+ s.Printf ("\n\t%s", matches.GetStringAtIndex(match_idx));
+ }
+ s.Printf ("\n");
+ result.AppendError(s.GetData());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else if (!sub_cmd_obj)
+ {
+ result.AppendErrorWithFormat("'%s' is not a known command.\n"
+ "Try 'help' to see a current list of commands.\n",
+ cmd_string.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ result.GetOutputStream().Printf("'%s' is not a known command.\n"
+ "Try 'help' to see a current list of commands.\n"
+ "The closest match is '%s'. Help on it follows.\n\n",
+ cmd_string.c_str(),
+ sub_cmd_obj->GetCommandName());
+ }
+ }
+
+ sub_cmd_obj->GenerateHelpText(result);
+
+ if (is_alias_command)
+ {
+ StreamString sstr;
+ m_interpreter.GetAliasHelp (alias_name.c_str(), cmd_obj->GetCommandName(), sstr);
+ result.GetOutputStream().Printf ("\n'%s' is an abbreviation for %s\n", alias_name.c_str(), sstr.GetData());
+ }
+ }
+ else if (matches.GetSize() > 0)
+ {
+ Stream &output_strm = result.GetOutputStream();
+ output_strm.Printf("Help requested with ambiguous command name, possible completions:\n");
+ const size_t match_count = matches.GetSize();
+ for (size_t i = 0; i < match_count; i++)
+ {
+ output_strm.Printf("\t%s\n", matches.GetStringAtIndex(i));
+ }
+ }
+ else
+ {
+ // Maybe the user is asking for help about a command argument rather than a command.
+ const CommandArgumentType arg_type = CommandObject::LookupArgumentName (command.GetArgumentAtIndex (0));
+ if (arg_type != eArgTypeLastArg)
+ {
+ Stream &output_strm = result.GetOutputStream ();
+ CommandObject::GetArgumentHelp (output_strm, arg_type, m_interpreter);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat
+ ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n",
+ command.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+
+ return result.Succeeded();
+}
+
+int
+CommandObjectHelp::HandleCompletion
+(
+ Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches
+)
+{
+ // Return the completions of the commands in the help system:
+ if (cursor_index == 0)
+ {
+ return m_interpreter.HandleCompletionMatches (input,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ }
+ else
+ {
+ CommandObject *cmd_obj = m_interpreter.GetCommandObject (input.GetArgumentAtIndex(0));
+
+ // The command that they are getting help on might be ambiguous, in which case we should complete that,
+ // otherwise complete with the command the user is getting help on...
+
+ if (cmd_obj)
+ {
+ input.Shift();
+ cursor_index--;
+ return cmd_obj->HandleCompletion (input,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ }
+ else
+ {
+ return m_interpreter.HandleCompletionMatches (input,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ }
+ }
+}
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectHelp.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectHelp.h
new file mode 100644
index 0000000..6e8f9d4
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectHelp.h
@@ -0,0 +1,119 @@
+//===-- CommandObjectHelp.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_CommandObjectHelp_h_
+#define liblldb_CommandObjectHelp_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/Options.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectHelp
+//-------------------------------------------------------------------------
+
+class CommandObjectHelp : public CommandObjectParsed
+{
+public:
+
+ CommandObjectHelp (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectHelp ();
+
+ virtual int
+ HandleCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches);
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_show_aliases = true;
+ break;
+ case 'u':
+ m_show_user_defined = false;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_show_aliases = false;
+ m_show_user_defined = true;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_show_aliases;
+ bool m_show_user_defined;
+ };
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result);
+
+private:
+ CommandOptions m_options;
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectHelp_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectLog.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectLog.cpp
new file mode 100644
index 0000000..5fb7915
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectLog.cpp
@@ -0,0 +1,503 @@
+//===-- CommandObjectLog.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 "CommandObjectLog.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/Timer.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+class CommandObjectLogEnable : public CommandObjectParsed
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectLogEnable(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "log enable",
+ "Enable logging for a single log channel.",
+ NULL),
+ m_options (interpreter)
+ {
+
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData channel_arg;
+ CommandArgumentData category_arg;
+
+ // Define the first (and only) variant of this arg.
+ channel_arg.arg_type = eArgTypeLogChannel;
+ channel_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (channel_arg);
+
+ category_arg.arg_type = eArgTypeLogCategory;
+ category_arg.arg_repetition = eArgRepeatPlus;
+
+ arg2.push_back (category_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ }
+
+ virtual
+ ~CommandObjectLogEnable()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+// int
+// HandleArgumentCompletion (Args &input,
+// int &cursor_index,
+// int &cursor_char_position,
+// OptionElementVector &opt_element_vector,
+// int match_start_point,
+// int max_return_elements,
+// bool &word_complete,
+// StringList &matches)
+// {
+// std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+// completion_str.erase (cursor_char_position);
+//
+// if (cursor_index == 1)
+// {
+// //
+// Log::AutoCompleteChannelName (completion_str.c_str(), matches);
+// }
+// return matches.GetSize();
+// }
+//
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ log_file (),
+ log_options (0)
+ {
+ }
+
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'f': log_file.SetFile(option_arg, true); break;
+ case 't': log_options |= LLDB_LOG_OPTION_THREADSAFE; break;
+ case 'v': log_options |= LLDB_LOG_OPTION_VERBOSE; break;
+ case 'g': log_options |= LLDB_LOG_OPTION_DEBUG; break;
+ case 's': log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE; break;
+ case 'T': log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP; break;
+ case 'p': log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;break;
+ case 'n': log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME; break;
+ case 'S': log_options |= LLDB_LOG_OPTION_BACKTRACE; break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ log_file.Clear();
+ log_options = 0;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ FileSpec log_file;
+ uint32_t log_options;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result)
+ {
+ if (args.GetArgumentCount() < 2)
+ {
+ result.AppendErrorWithFormat("%s takes a log channel and one or more log types.\n", m_cmd_name.c_str());
+ }
+ else
+ {
+ std::string channel(args.GetArgumentAtIndex(0));
+ args.Shift (); // Shift off the channel
+ char log_file[PATH_MAX];
+ if (m_options.log_file)
+ m_options.log_file.GetPath(log_file, sizeof(log_file));
+ else
+ log_file[0] = '\0';
+ bool success = m_interpreter.GetDebugger().EnableLog (channel.c_str(),
+ args.GetConstArgumentVector(),
+ log_file,
+ m_options.log_options,
+ result.GetErrorStream());
+ if (success)
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ else
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectLogEnable::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, 0, eArgTypeFilename, "Set the destination file to log to."},
+{ LLDB_OPT_SET_1, false, "threadsafe", 't', no_argument, NULL, 0, eArgTypeNone, "Enable thread safe logging to avoid interweaved log lines." },
+{ LLDB_OPT_SET_1, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone, "Enable verbose logging." },
+{ LLDB_OPT_SET_1, false, "debug", 'g', no_argument, NULL, 0, eArgTypeNone, "Enable debug logging." },
+{ LLDB_OPT_SET_1, false, "sequence", 's', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with an increasing integer sequence id." },
+{ LLDB_OPT_SET_1, false, "timestamp", 'T', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with a timestamp." },
+{ LLDB_OPT_SET_1, false, "pid-tid", 'p', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with the process and thread ID that generates the log line." },
+{ LLDB_OPT_SET_1, false, "thread-name",'n', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with the thread name for the thread that generates the log line." },
+{ LLDB_OPT_SET_1, false, "stack", 'S', no_argument, NULL, 0, eArgTypeNone, "Append a stack backtrace to each log line." },
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+class CommandObjectLogDisable : public CommandObjectParsed
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectLogDisable(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "log disable",
+ "Disable one or more log channel categories.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData channel_arg;
+ CommandArgumentData category_arg;
+
+ // Define the first (and only) variant of this arg.
+ channel_arg.arg_type = eArgTypeLogChannel;
+ channel_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (channel_arg);
+
+ category_arg.arg_type = eArgTypeLogCategory;
+ category_arg.arg_repetition = eArgRepeatPlus;
+
+ arg2.push_back (category_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ }
+
+ virtual
+ ~CommandObjectLogDisable()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result)
+ {
+ const size_t argc = args.GetArgumentCount();
+ if (argc == 0)
+ {
+ result.AppendErrorWithFormat("%s takes a log channel and one or more log types.\n", m_cmd_name.c_str());
+ }
+ else
+ {
+ Log::Callbacks log_callbacks;
+
+ std::string channel(args.GetArgumentAtIndex(0));
+ args.Shift (); // Shift off the channel
+ if (Log::GetLogChannelCallbacks (ConstString(channel.c_str()), log_callbacks))
+ {
+ log_callbacks.disable (args.GetConstArgumentVector(), &result.GetErrorStream());
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else if (channel == "all")
+ {
+ Log::DisableAllLogChannels(&result.GetErrorStream());
+ }
+ else
+ {
+ LogChannelSP log_channel_sp (LogChannel::FindPlugin(channel.c_str()));
+ if (log_channel_sp)
+ {
+ log_channel_sp->Disable(args.GetConstArgumentVector(), &result.GetErrorStream());
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0));
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+class CommandObjectLogList : public CommandObjectParsed
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectLogList(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "log list",
+ "List the log categories for one or more log channels. If none specified, lists them all.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData channel_arg;
+
+ // Define the first (and only) variant of this arg.
+ channel_arg.arg_type = eArgTypeLogChannel;
+ channel_arg.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (channel_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectLogList()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result)
+ {
+ const size_t argc = args.GetArgumentCount();
+ if (argc == 0)
+ {
+ Log::ListAllLogChannels (&result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ for (size_t i=0; i<argc; ++i)
+ {
+ Log::Callbacks log_callbacks;
+
+ std::string channel(args.GetArgumentAtIndex(i));
+ if (Log::GetLogChannelCallbacks (ConstString(channel.c_str()), log_callbacks))
+ {
+ log_callbacks.list_categories (&result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else if (channel == "all")
+ {
+ Log::ListAllLogChannels (&result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ LogChannelSP log_channel_sp (LogChannel::FindPlugin(channel.c_str()));
+ if (log_channel_sp)
+ {
+ log_channel_sp->ListCategories(&result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0));
+ }
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+class CommandObjectLogTimer : public CommandObjectParsed
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectLogTimer(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "log timers",
+ "Enable, disable, dump, and reset LLDB internal performance timers.",
+ "log timers < enable <depth> | disable | dump | increment <bool> | reset >")
+ {
+ }
+
+ virtual
+ ~CommandObjectLogTimer()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result)
+ {
+ const size_t argc = args.GetArgumentCount();
+ result.SetStatus(eReturnStatusFailed);
+
+ if (argc == 1)
+ {
+ const char *sub_command = args.GetArgumentAtIndex(0);
+
+ if (strcasecmp(sub_command, "enable") == 0)
+ {
+ Timer::SetDisplayDepth (UINT32_MAX);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else if (strcasecmp(sub_command, "disable") == 0)
+ {
+ Timer::DumpCategoryTimes (&result.GetOutputStream());
+ Timer::SetDisplayDepth (0);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else if (strcasecmp(sub_command, "dump") == 0)
+ {
+ Timer::DumpCategoryTimes (&result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else if (strcasecmp(sub_command, "reset") == 0)
+ {
+ Timer::ResetCategoryTimes ();
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+
+ }
+ else if (argc == 2)
+ {
+ const char *sub_command = args.GetArgumentAtIndex(0);
+
+ if (strcasecmp(sub_command, "enable") == 0)
+ {
+ bool success;
+ uint32_t depth = Args::StringToUInt32(args.GetArgumentAtIndex(1), 0, 0, &success);
+ if (success)
+ {
+ Timer::SetDisplayDepth (depth);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ result.AppendError("Could not convert enable depth to an unsigned integer.");
+ }
+ if (strcasecmp(sub_command, "increment") == 0)
+ {
+ bool success;
+ bool increment = Args::StringToBoolean(args.GetArgumentAtIndex(1), false, &success);
+ if (success)
+ {
+ Timer::SetQuiet (!increment);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ result.AppendError("Could not convert increment value to boolean.");
+ }
+ }
+
+ if (!result.Succeeded())
+ {
+ result.AppendError("Missing subcommand");
+ result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
+ }
+ return result.Succeeded();
+ }
+};
+
+//----------------------------------------------------------------------
+// CommandObjectLog constructor
+//----------------------------------------------------------------------
+CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "log",
+ "A set of commands for operating on logs.",
+ "log <command> [<command-options>]")
+{
+ LoadSubCommand ("enable", CommandObjectSP (new CommandObjectLogEnable (interpreter)));
+ LoadSubCommand ("disable", CommandObjectSP (new CommandObjectLogDisable (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectLogList (interpreter)));
+ LoadSubCommand ("timers", CommandObjectSP (new CommandObjectLogTimer (interpreter)));
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CommandObjectLog::~CommandObjectLog()
+{
+}
+
+
+
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectLog.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectLog.h
new file mode 100644
index 0000000..3e731fa
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectLog.h
@@ -0,0 +1,48 @@
+//===-- CommandObjectLog.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_CommandObjectLog_h_
+#define liblldb_CommandObjectLog_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectLog
+//-------------------------------------------------------------------------
+
+class CommandObjectLog : public CommandObjectMultiword
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectLog(CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectLog();
+
+private:
+ //------------------------------------------------------------------
+ // For CommandObjectLog only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectLog);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectLog_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectMemory.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectMemory.cpp
new file mode 100644
index 0000000..4725a4d
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectMemory.cpp
@@ -0,0 +1,1370 @@
+//===-- CommandObjectMemory.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 "CommandObjectMemory.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Interpreter/OptionGroupOutputFile.h"
+#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
+#include "lldb/Interpreter/OptionValueString.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static OptionDefinition
+g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "num-per-line" ,'l', required_argument, NULL, 0, eArgTypeNumberPerLine ,"The number of items per line to display."},
+ { LLDB_OPT_SET_2, false, "binary" ,'b', no_argument , NULL, 0, eArgTypeNone ,"If true, memory will be saved as binary. If false, the memory is saved save as an ASCII dump that uses the format, size, count and number per line settings."},
+ { LLDB_OPT_SET_3, true , "type" ,'t', required_argument, NULL, 0, eArgTypeNone ,"The name of a type to view memory as."},
+ { LLDB_OPT_SET_1|
+ LLDB_OPT_SET_2|
+ LLDB_OPT_SET_3, false, "force" ,'r', no_argument, NULL, 0, eArgTypeNone ,"Necessary if reading over target.max-memory-read-size bytes."},
+};
+
+
+
+class OptionGroupReadMemory : public OptionGroup
+{
+public:
+
+ OptionGroupReadMemory () :
+ m_num_per_line (1,1),
+ m_output_as_binary (false),
+ m_view_as_type()
+ {
+ }
+
+ virtual
+ ~OptionGroupReadMemory ()
+ {
+ }
+
+
+ virtual uint32_t
+ GetNumDefinitions ()
+ {
+ return sizeof (g_option_table) / sizeof (OptionDefinition);
+ }
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ virtual Error
+ 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 'l':
+ error = m_num_per_line.SetValueFromCString (option_arg);
+ if (m_num_per_line.GetCurrentValue() == 0)
+ error.SetErrorStringWithFormat("invalid value for --num-per-line option '%s'", option_arg);
+ break;
+
+ case 'b':
+ m_output_as_binary = true;
+ break;
+
+ case 't':
+ error = m_view_as_type.SetValueFromCString (option_arg);
+ break;
+
+ case 'r':
+ m_force = true;
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter)
+ {
+ m_num_per_line.Clear();
+ m_output_as_binary = false;
+ m_view_as_type.Clear();
+ m_force = false;
+ }
+
+ Error
+ FinalizeSettings (Target *target, OptionGroupFormat& format_options)
+ {
+ Error error;
+ OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue();
+ OptionValueUInt64 &count_value = format_options.GetCountValue();
+ const bool byte_size_option_set = byte_size_value.OptionWasSet();
+ const bool num_per_line_option_set = m_num_per_line.OptionWasSet();
+ const bool count_option_set = format_options.GetCountValue().OptionWasSet();
+
+ switch (format_options.GetFormat())
+ {
+ default:
+ break;
+
+ case eFormatBoolean:
+ if (!byte_size_option_set)
+ byte_size_value = 1;
+ if (!num_per_line_option_set)
+ m_num_per_line = 1;
+ if (!count_option_set)
+ format_options.GetCountValue() = 8;
+ break;
+
+ case eFormatCString:
+ break;
+
+ case eFormatInstruction:
+ if (count_option_set)
+ byte_size_value = target->GetArchitecture().GetMaximumOpcodeByteSize();
+ m_num_per_line = 1;
+ break;
+
+ case eFormatAddressInfo:
+ if (!byte_size_option_set)
+ byte_size_value = target->GetArchitecture().GetAddressByteSize();
+ m_num_per_line = 1;
+ if (!count_option_set)
+ format_options.GetCountValue() = 8;
+ break;
+
+ case eFormatPointer:
+ byte_size_value = target->GetArchitecture().GetAddressByteSize();
+ if (!num_per_line_option_set)
+ m_num_per_line = 4;
+ if (!count_option_set)
+ format_options.GetCountValue() = 8;
+ break;
+
+ case eFormatBinary:
+ case eFormatFloat:
+ case eFormatOctal:
+ case eFormatDecimal:
+ case eFormatEnum:
+ case eFormatUnicode16:
+ case eFormatUnicode32:
+ case eFormatUnsigned:
+ case eFormatHexFloat:
+ if (!byte_size_option_set)
+ byte_size_value = 4;
+ if (!num_per_line_option_set)
+ m_num_per_line = 1;
+ if (!count_option_set)
+ format_options.GetCountValue() = 8;
+ break;
+
+ case eFormatBytes:
+ case eFormatBytesWithASCII:
+ if (byte_size_option_set)
+ {
+ if (byte_size_value > 1)
+ error.SetErrorStringWithFormat ("display format (bytes/bytes with ascii) conflicts with the specified byte size %" PRIu64 "\n"
+ "\tconsider using a different display format or don't specify the byte size",
+ byte_size_value.GetCurrentValue());
+ }
+ else
+ byte_size_value = 1;
+ if (!num_per_line_option_set)
+ m_num_per_line = 16;
+ if (!count_option_set)
+ format_options.GetCountValue() = 32;
+ break;
+ case eFormatCharArray:
+ case eFormatChar:
+ case eFormatCharPrintable:
+ if (!byte_size_option_set)
+ byte_size_value = 1;
+ if (!num_per_line_option_set)
+ m_num_per_line = 32;
+ if (!count_option_set)
+ format_options.GetCountValue() = 64;
+ break;
+ case eFormatComplex:
+ if (!byte_size_option_set)
+ byte_size_value = 8;
+ if (!num_per_line_option_set)
+ m_num_per_line = 1;
+ if (!count_option_set)
+ format_options.GetCountValue() = 8;
+ break;
+ case eFormatComplexInteger:
+ if (!byte_size_option_set)
+ byte_size_value = 8;
+ if (!num_per_line_option_set)
+ m_num_per_line = 1;
+ if (!count_option_set)
+ format_options.GetCountValue() = 8;
+ break;
+ case eFormatHex:
+ if (!byte_size_option_set)
+ byte_size_value = 4;
+ if (!num_per_line_option_set)
+ {
+ switch (byte_size_value)
+ {
+ case 1:
+ case 2:
+ m_num_per_line = 8;
+ break;
+ case 4:
+ m_num_per_line = 4;
+ break;
+ case 8:
+ m_num_per_line = 2;
+ break;
+ default:
+ m_num_per_line = 1;
+ break;
+ }
+ }
+ if (!count_option_set)
+ count_value = 8;
+ break;
+
+ case eFormatVectorOfChar:
+ case eFormatVectorOfSInt8:
+ case eFormatVectorOfUInt8:
+ case eFormatVectorOfSInt16:
+ case eFormatVectorOfUInt16:
+ case eFormatVectorOfSInt32:
+ case eFormatVectorOfUInt32:
+ case eFormatVectorOfSInt64:
+ case eFormatVectorOfUInt64:
+ case eFormatVectorOfFloat32:
+ case eFormatVectorOfFloat64:
+ case eFormatVectorOfUInt128:
+ if (!byte_size_option_set)
+ byte_size_value = 128;
+ if (!num_per_line_option_set)
+ m_num_per_line = 1;
+ if (!count_option_set)
+ count_value = 4;
+ break;
+ }
+ return error;
+ }
+
+ bool
+ AnyOptionWasSet () const
+ {
+ return m_num_per_line.OptionWasSet() ||
+ m_output_as_binary ||
+ m_view_as_type.OptionWasSet();
+ }
+
+ OptionValueUInt64 m_num_per_line;
+ bool m_output_as_binary;
+ OptionValueString m_view_as_type;
+ bool m_force;
+};
+
+
+
+//----------------------------------------------------------------------
+// Read memory from the inferior process
+//----------------------------------------------------------------------
+class CommandObjectMemoryRead : public CommandObjectParsed
+{
+public:
+
+ CommandObjectMemoryRead (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "memory read",
+ "Read from the memory of the process being debugged.",
+ NULL,
+ eFlagRequiresTarget | eFlagProcessMustBePaused),
+ m_option_group (interpreter),
+ m_format_options (eFormatBytesWithASCII, 1, 8),
+ m_memory_options (),
+ m_outfile_options (),
+ m_varobj_options(),
+ m_next_addr(LLDB_INVALID_ADDRESS),
+ m_prev_byte_size(0),
+ m_prev_format_options (eFormatBytesWithASCII, 1, 8),
+ m_prev_memory_options (),
+ m_prev_outfile_options (),
+ m_prev_varobj_options()
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData start_addr_arg;
+ CommandArgumentData end_addr_arg;
+
+ // Define the first (and only) variant of this arg.
+ start_addr_arg.arg_type = eArgTypeAddressOrExpression;
+ start_addr_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (start_addr_arg);
+
+ // Define the first (and only) variant of this arg.
+ end_addr_arg.arg_type = eArgTypeAddressOrExpression;
+ end_addr_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (end_addr_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+
+ // Add the "--format" and "--count" options to group 1 and 3
+ m_option_group.Append (&m_format_options,
+ OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_COUNT,
+ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
+ m_option_group.Append (&m_format_options,
+ OptionGroupFormat::OPTION_GROUP_GDB_FMT,
+ LLDB_OPT_SET_1 | LLDB_OPT_SET_3);
+ // Add the "--size" option to group 1 and 2
+ m_option_group.Append (&m_format_options,
+ OptionGroupFormat::OPTION_GROUP_SIZE,
+ LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
+ m_option_group.Append (&m_memory_options);
+ m_option_group.Append (&m_outfile_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
+ m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectMemoryRead ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+ virtual const char *GetRepeatCommand (Args &current_command_args, uint32_t index)
+ {
+ return m_cmd_name.c_str();
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ // No need to check "target" for validity as eFlagRequiresTarget ensures it is valid
+ Target *target = m_exe_ctx.GetTargetPtr();
+
+ const size_t argc = command.GetArgumentCount();
+
+ if ((argc == 0 && m_next_addr == LLDB_INVALID_ADDRESS) || argc > 2)
+ {
+ result.AppendErrorWithFormat ("%s takes a start address expression with an optional end address expression.\n", m_cmd_name.c_str());
+ result.AppendRawWarning("Expressions should be quoted if they contain spaces or other special characters.\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ ClangASTType clang_ast_type;
+ Error error;
+
+ const char *view_as_type_cstr = m_memory_options.m_view_as_type.GetCurrentValue();
+ if (view_as_type_cstr && view_as_type_cstr[0])
+ {
+ // We are viewing memory as a type
+
+ SymbolContext sc;
+ const bool exact_match = false;
+ TypeList type_list;
+ uint32_t reference_count = 0;
+ uint32_t pointer_count = 0;
+ size_t idx;
+
+#define ALL_KEYWORDS \
+ KEYWORD("const") \
+ KEYWORD("volatile") \
+ KEYWORD("restrict") \
+ KEYWORD("struct") \
+ KEYWORD("class") \
+ KEYWORD("union")
+
+#define KEYWORD(s) s,
+ static const char *g_keywords[] =
+ {
+ ALL_KEYWORDS
+ };
+#undef KEYWORD
+
+#define KEYWORD(s) (sizeof(s) - 1),
+ static const int g_keyword_lengths[] =
+ {
+ ALL_KEYWORDS
+ };
+#undef KEYWORD
+
+#undef ALL_KEYWORDS
+
+ static size_t g_num_keywords = sizeof(g_keywords) / sizeof(const char *);
+ std::string type_str(view_as_type_cstr);
+
+ // Remove all instances of g_keywords that are followed by spaces
+ for (size_t i = 0; i < g_num_keywords; ++i)
+ {
+ const char *keyword = g_keywords[i];
+ int keyword_len = g_keyword_lengths[i];
+
+ idx = 0;
+ while ((idx = type_str.find (keyword, idx)) != std::string::npos)
+ {
+ if (type_str[idx + keyword_len] == ' ' || type_str[idx + keyword_len] == '\t')
+ {
+ type_str.erase(idx, keyword_len+1);
+ idx = 0;
+ }
+ else
+ {
+ idx += keyword_len;
+ }
+ }
+ }
+ bool done = type_str.empty();
+ //
+ idx = type_str.find_first_not_of (" \t");
+ if (idx > 0 && idx != std::string::npos)
+ type_str.erase (0, idx);
+ while (!done)
+ {
+ // Strip trailing spaces
+ if (type_str.empty())
+ done = true;
+ else
+ {
+ switch (type_str[type_str.size()-1])
+ {
+ case '*':
+ ++pointer_count;
+ // fall through...
+ case ' ':
+ case '\t':
+ type_str.erase(type_str.size()-1);
+ break;
+
+ case '&':
+ if (reference_count == 0)
+ {
+ reference_count = 1;
+ type_str.erase(type_str.size()-1);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("invalid type string: '%s'\n", view_as_type_cstr);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ break;
+
+ default:
+ done = true;
+ break;
+ }
+ }
+ }
+
+ ConstString lookup_type_name(type_str.c_str());
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ sc = frame->GetSymbolContext (eSymbolContextModule);
+ if (sc.module_sp)
+ {
+ sc.module_sp->FindTypes (sc,
+ lookup_type_name,
+ exact_match,
+ 1,
+ type_list);
+ }
+ }
+ if (type_list.GetSize() == 0)
+ {
+ target->GetImages().FindTypes (sc,
+ lookup_type_name,
+ exact_match,
+ 1,
+ type_list);
+ }
+
+ if (type_list.GetSize() == 0 && lookup_type_name.GetCString() && *lookup_type_name.GetCString() == '$')
+ {
+ clang::TypeDecl *tdecl = target->GetPersistentVariables().GetPersistentType(ConstString(lookup_type_name));
+ if (tdecl)
+ {
+ clang_ast_type.SetClangType(&tdecl->getASTContext(),(lldb::clang_type_t)tdecl->getTypeForDecl());
+ }
+ }
+
+ if (clang_ast_type.IsValid() == false)
+ {
+ if (type_list.GetSize() == 0)
+ {
+ result.AppendErrorWithFormat ("unable to find any types that match the raw type '%s' for full type '%s'\n",
+ lookup_type_name.GetCString(),
+ view_as_type_cstr);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ TypeSP type_sp (type_list.GetTypeAtIndex(0));
+ clang_ast_type = type_sp->GetClangFullType();
+ }
+ }
+
+ while (pointer_count > 0)
+ {
+ ClangASTType pointer_type = clang_ast_type.GetPointerType();
+ if (pointer_type.IsValid())
+ clang_ast_type = pointer_type;
+ else
+ {
+ result.AppendError ("unable make a pointer type\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ --pointer_count;
+ }
+
+ m_format_options.GetByteSizeValue() = clang_ast_type.GetByteSize();
+
+ if (m_format_options.GetByteSizeValue() == 0)
+ {
+ result.AppendErrorWithFormat ("unable to get the byte size of the type '%s'\n",
+ view_as_type_cstr);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (!m_format_options.GetCountValue().OptionWasSet())
+ m_format_options.GetCountValue() = 1;
+ }
+ else
+ {
+ error = m_memory_options.FinalizeSettings (target, m_format_options);
+ }
+
+ // Look for invalid combinations of settings
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ lldb::addr_t addr;
+ size_t total_byte_size = 0;
+ if (argc == 0)
+ {
+ // Use the last address and byte size and all options as they were
+ // if no options have been set
+ addr = m_next_addr;
+ total_byte_size = m_prev_byte_size;
+ clang_ast_type = m_prev_clang_ast_type;
+ if (!m_format_options.AnyOptionWasSet() &&
+ !m_memory_options.AnyOptionWasSet() &&
+ !m_outfile_options.AnyOptionWasSet() &&
+ !m_varobj_options.AnyOptionWasSet())
+ {
+ m_format_options = m_prev_format_options;
+ m_memory_options = m_prev_memory_options;
+ m_outfile_options = m_prev_outfile_options;
+ m_varobj_options = m_prev_varobj_options;
+ }
+ }
+
+ size_t item_count = m_format_options.GetCountValue().GetCurrentValue();
+ size_t item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
+ const size_t num_per_line = m_memory_options.m_num_per_line.GetCurrentValue();
+
+ if (total_byte_size == 0)
+ {
+ total_byte_size = item_count * item_byte_size;
+ if (total_byte_size == 0)
+ total_byte_size = 32;
+ }
+
+ if (argc > 0)
+ addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, &error);
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ result.AppendError("invalid start address expression.");
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (argc == 2)
+ {
+ lldb::addr_t end_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0);
+ if (end_addr == LLDB_INVALID_ADDRESS)
+ {
+ result.AppendError("invalid end address expression.");
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (end_addr <= addr)
+ {
+ result.AppendErrorWithFormat("end address (0x%" PRIx64 ") must be greater that the start address (0x%" PRIx64 ").\n", end_addr, addr);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (m_format_options.GetCountValue().OptionWasSet())
+ {
+ result.AppendErrorWithFormat("specify either the end address (0x%" PRIx64 ") or the count (--count %lu), not both.\n", end_addr, item_count);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ total_byte_size = end_addr - addr;
+ item_count = total_byte_size / item_byte_size;
+ }
+
+ uint32_t max_unforced_size = target->GetMaximumMemReadSize();
+
+ if (total_byte_size > max_unforced_size && !m_memory_options.m_force)
+ {
+ result.AppendErrorWithFormat("Normally, \'memory read\' will not read over %" PRIu32 " bytes of data.\n",max_unforced_size);
+ result.AppendErrorWithFormat("Please use --force to override this restriction just once.\n");
+ result.AppendErrorWithFormat("or set target.max-memory-read-size if you will often need a larger limit.\n");
+ return false;
+ }
+
+ DataBufferSP data_sp;
+ size_t bytes_read = 0;
+ if (clang_ast_type.GetOpaqueQualType())
+ {
+ // Make sure we don't display our type as ASCII bytes like the default memory read
+ if (m_format_options.GetFormatValue().OptionWasSet() == false)
+ m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault);
+
+ bytes_read = clang_ast_type.GetByteSize() * m_format_options.GetCountValue().GetCurrentValue();
+ }
+ else if (m_format_options.GetFormatValue().GetCurrentValue() != eFormatCString)
+ {
+ data_sp.reset (new DataBufferHeap (total_byte_size, '\0'));
+ if (data_sp->GetBytes() == NULL)
+ {
+ result.AppendErrorWithFormat ("can't allocate 0x%zx bytes for the memory read buffer, specify a smaller size to read", total_byte_size);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ Address address(addr, NULL);
+ bytes_read = target->ReadMemory(address, false, data_sp->GetBytes (), data_sp->GetByteSize(), error);
+ if (bytes_read == 0)
+ {
+ const char *error_cstr = error.AsCString();
+ if (error_cstr && error_cstr[0])
+ {
+ result.AppendError(error_cstr);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr);
+ }
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (bytes_read < total_byte_size)
+ result.AppendWarningWithFormat("Not all bytes (%lu/%lu) were able to be read from 0x%" PRIx64 ".\n", bytes_read, total_byte_size, addr);
+ }
+ else
+ {
+ // we treat c-strings as a special case because they do not have a fixed size
+ if (m_format_options.GetByteSizeValue().OptionWasSet() && !m_format_options.HasGDBFormat())
+ item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
+ else
+ item_byte_size = target->GetMaximumSizeOfStringSummary();
+ if (!m_format_options.GetCountValue().OptionWasSet())
+ item_count = 1;
+ data_sp.reset (new DataBufferHeap ((item_byte_size+1) * item_count, '\0')); // account for NULLs as necessary
+ if (data_sp->GetBytes() == NULL)
+ {
+ result.AppendErrorWithFormat ("can't allocate 0x%" PRIx64 " bytes for the memory read buffer, specify a smaller size to read", (uint64_t)((item_byte_size+1) * item_count));
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ uint8_t *data_ptr = data_sp->GetBytes();
+ auto data_addr = addr;
+ auto count = item_count;
+ item_count = 0;
+ while (item_count < count)
+ {
+ std::string buffer;
+ buffer.resize(item_byte_size+1,0);
+ Error error;
+ size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0], item_byte_size+1, error);
+ if (error.Fail())
+ {
+ result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ if (item_byte_size == read)
+ {
+ result.AppendWarningWithFormat("unable to find a NULL terminated string at 0x%" PRIx64 ".Consider increasing the maximum read length.\n", data_addr);
+ break;
+ }
+ read+=1; // account for final NULL byte
+ memcpy(data_ptr, &buffer[0], read);
+ data_ptr += read;
+ data_addr += read;
+ bytes_read += read;
+ item_count++; // if we break early we know we only read item_count strings
+ }
+ data_sp.reset(new DataBufferHeap(data_sp->GetBytes(),bytes_read+1));
+ }
+
+ m_next_addr = addr + bytes_read;
+ m_prev_byte_size = bytes_read;
+ m_prev_format_options = m_format_options;
+ m_prev_memory_options = m_memory_options;
+ m_prev_outfile_options = m_outfile_options;
+ m_prev_varobj_options = m_varobj_options;
+ m_prev_clang_ast_type = clang_ast_type;
+
+ StreamFile outfile_stream;
+ Stream *output_stream = NULL;
+ const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue();
+ if (outfile_spec)
+ {
+ char path[PATH_MAX];
+ outfile_spec.GetPath (path, sizeof(path));
+
+ uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
+ const bool append = m_outfile_options.GetAppend().GetCurrentValue();
+ if (append)
+ open_options |= File::eOpenOptionAppend;
+
+ if (outfile_stream.GetFile ().Open (path, open_options).Success())
+ {
+ if (m_memory_options.m_output_as_binary)
+ {
+ const size_t bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read);
+ if (bytes_written > 0)
+ {
+ result.GetOutputStream().Printf ("%zi bytes %s to '%s'\n",
+ bytes_written,
+ append ? "appended" : "written",
+ path);
+ return true;
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Failed to write %" PRIu64 " bytes to '%s'.\n", (uint64_t)bytes_read, path);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ // We are going to write ASCII to the file just point the
+ // output_stream to our outfile_stream...
+ output_stream = &outfile_stream;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n", path, append ? "append" : "write");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ output_stream = &result.GetOutputStream();
+ }
+
+
+ ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
+ if (clang_ast_type.GetOpaqueQualType())
+ {
+ for (uint32_t i = 0; i<item_count; ++i)
+ {
+ addr_t item_addr = addr + (i * item_byte_size);
+ Address address (item_addr);
+ StreamString name_strm;
+ name_strm.Printf ("0x%" PRIx64, item_addr);
+ ValueObjectSP valobj_sp (ValueObjectMemory::Create (exe_scope,
+ name_strm.GetString().c_str(),
+ address,
+ clang_ast_type));
+ if (valobj_sp)
+ {
+ Format format = m_format_options.GetFormat();
+ if (format != eFormatDefault)
+ valobj_sp->SetFormat (format);
+
+ ValueObject::DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(false,format));
+
+ ValueObject::DumpValueObject (*output_stream,
+ valobj_sp.get(),
+ options);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("failed to create a value object for: (%s) %s\n",
+ view_as_type_cstr,
+ name_strm.GetString().c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ DataExtractor data (data_sp,
+ target->GetArchitecture().GetByteOrder(),
+ target->GetArchitecture().GetAddressByteSize());
+
+ Format format = m_format_options.GetFormat();
+ if ( ( (format == eFormatChar) || (format == eFormatCharPrintable) )
+ && (item_byte_size != 1)
+ && (item_count == 1))
+ {
+ // this turns requests such as
+ // memory read -fc -s10 -c1 *charPtrPtr
+ // which make no sense (what is a char of size 10?)
+ // into a request for fetching 10 chars of size 1 from the same memory location
+ format = eFormatCharArray;
+ item_count = item_byte_size;
+ item_byte_size = 1;
+ }
+
+ assert (output_stream);
+ size_t bytes_dumped = data.Dump (output_stream,
+ 0,
+ format,
+ item_byte_size,
+ item_count,
+ num_per_line,
+ addr,
+ 0,
+ 0,
+ exe_scope);
+ m_next_addr = addr + bytes_dumped;
+ output_stream->EOL();
+ return true;
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupFormat m_format_options;
+ OptionGroupReadMemory m_memory_options;
+ OptionGroupOutputFile m_outfile_options;
+ OptionGroupValueObjectDisplay m_varobj_options;
+ lldb::addr_t m_next_addr;
+ lldb::addr_t m_prev_byte_size;
+ OptionGroupFormat m_prev_format_options;
+ OptionGroupReadMemory m_prev_memory_options;
+ OptionGroupOutputFile m_prev_outfile_options;
+ OptionGroupValueObjectDisplay m_prev_varobj_options;
+ ClangASTType m_prev_clang_ast_type;
+};
+
+
+OptionDefinition
+g_memory_write_option_table[] =
+{
+{ LLDB_OPT_SET_1, true, "infile", 'i', required_argument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."},
+{ LLDB_OPT_SET_1, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset, "Start writng bytes from an offset within the input file."},
+};
+
+
+//----------------------------------------------------------------------
+// Write memory to the inferior process
+//----------------------------------------------------------------------
+class CommandObjectMemoryWrite : public CommandObjectParsed
+{
+public:
+
+ class OptionGroupWriteMemory : public OptionGroup
+ {
+ public:
+ OptionGroupWriteMemory () :
+ OptionGroup()
+ {
+ }
+
+ virtual
+ ~OptionGroupWriteMemory ()
+ {
+ }
+
+ virtual uint32_t
+ GetNumDefinitions ()
+ {
+ return sizeof (g_memory_write_option_table) / sizeof (OptionDefinition);
+ }
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_memory_write_option_table;
+ }
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+ {
+ Error error;
+ const int short_option = g_memory_write_option_table[option_idx].short_option;
+
+ switch (short_option)
+ {
+ case 'i':
+ m_infile.SetFile (option_arg, true);
+ if (!m_infile.Exists())
+ {
+ m_infile.Clear();
+ error.SetErrorStringWithFormat("input file does not exist: '%s'", option_arg);
+ }
+ break;
+
+ case 'o':
+ {
+ bool success;
+ m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success);
+ if (!success)
+ {
+ error.SetErrorStringWithFormat("invalid offset string '%s'", option_arg);
+ }
+ }
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter)
+ {
+ m_infile.Clear();
+ m_infile_offset = 0;
+ }
+
+ FileSpec m_infile;
+ off_t m_infile_offset;
+ };
+
+ CommandObjectMemoryWrite (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "memory write",
+ "Write to the memory of the process being debugged.",
+ NULL,
+ eFlagRequiresProcess | eFlagProcessMustBeLaunched),
+ m_option_group (interpreter),
+ m_format_options (eFormatBytes, 1, UINT64_MAX),
+ m_memory_options ()
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData addr_arg;
+ CommandArgumentData value_arg;
+
+ // Define the first (and only) variant of this arg.
+ addr_arg.arg_type = eArgTypeAddress;
+ addr_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (addr_arg);
+
+ // Define the first (and only) variant of this arg.
+ value_arg.arg_type = eArgTypeValue;
+ value_arg.arg_repetition = eArgRepeatPlus;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (value_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+
+ m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_SIZE , LLDB_OPT_SET_1|LLDB_OPT_SET_2);
+ m_option_group.Append (&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
+ m_option_group.Finalize();
+
+ }
+
+ virtual
+ ~CommandObjectMemoryWrite ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+ bool
+ UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
+ {
+ if (total_byte_size > 8)
+ return false;
+
+ if (total_byte_size == 8)
+ return true;
+
+ const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
+ return uval64 <= max;
+ }
+
+ bool
+ SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
+ {
+ if (total_byte_size > 8)
+ return false;
+
+ if (total_byte_size == 8)
+ return true;
+
+ const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
+ const int64_t min = ~(max);
+ return min <= sval64 && sval64 <= max;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
+ Process *process = m_exe_ctx.GetProcessPtr();
+
+ const size_t argc = command.GetArgumentCount();
+
+ if (m_memory_options.m_infile)
+ {
+ if (argc < 1)
+ {
+ result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ else if (argc < 2)
+ {
+ result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ StreamString buffer (Stream::eBinary,
+ process->GetTarget().GetArchitecture().GetAddressByteSize(),
+ process->GetTarget().GetArchitecture().GetByteOrder());
+
+ OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue();
+ size_t item_byte_size = byte_size_value.GetCurrentValue();
+
+ Error error;
+ lldb::addr_t addr = Args::StringToAddress (&m_exe_ctx,
+ command.GetArgumentAtIndex(0),
+ LLDB_INVALID_ADDRESS,
+ &error);
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ result.AppendError("invalid address expression\n");
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_memory_options.m_infile)
+ {
+ size_t length = SIZE_MAX;
+ if (item_byte_size > 0)
+ length = item_byte_size;
+ lldb::DataBufferSP data_sp (m_memory_options.m_infile.ReadFileContents (m_memory_options.m_infile_offset, length));
+ if (data_sp)
+ {
+ length = data_sp->GetByteSize();
+ if (length > 0)
+ {
+ Error error;
+ size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error);
+
+ if (bytes_written == length)
+ {
+ // All bytes written
+ result.GetOutputStream().Printf("%" PRIu64 " bytes were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, addr);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else if (bytes_written > 0)
+ {
+ // Some byte written
+ result.GetOutputStream().Printf("%" PRIu64 " bytes of %" PRIu64 " requested were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, (uint64_t)length, addr);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Unable to read contents of file.\n");
+ result.SetStatus(eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+ else if (item_byte_size == 0)
+ {
+ if (m_format_options.GetFormat() == eFormatPointer)
+ item_byte_size = buffer.GetAddressByteSize();
+ else
+ item_byte_size = 1;
+ }
+
+ command.Shift(); // shift off the address argument
+ uint64_t uval64;
+ int64_t sval64;
+ bool success = false;
+ const size_t num_value_args = command.GetArgumentCount();
+ for (size_t i=0; i<num_value_args; ++i)
+ {
+ const char *value_str = command.GetArgumentAtIndex(i);
+
+ switch (m_format_options.GetFormat())
+ {
+ case kNumFormats:
+ case eFormatFloat: // TODO: add support for floats soon
+ case eFormatCharPrintable:
+ case eFormatBytesWithASCII:
+ case eFormatComplex:
+ case eFormatEnum:
+ case eFormatUnicode16:
+ case eFormatUnicode32:
+ case eFormatVectorOfChar:
+ case eFormatVectorOfSInt8:
+ case eFormatVectorOfUInt8:
+ case eFormatVectorOfSInt16:
+ case eFormatVectorOfUInt16:
+ case eFormatVectorOfSInt32:
+ case eFormatVectorOfUInt32:
+ case eFormatVectorOfSInt64:
+ case eFormatVectorOfUInt64:
+ case eFormatVectorOfFloat32:
+ case eFormatVectorOfFloat64:
+ case eFormatVectorOfUInt128:
+ case eFormatOSType:
+ case eFormatComplexInteger:
+ case eFormatAddressInfo:
+ case eFormatHexFloat:
+ case eFormatInstruction:
+ case eFormatVoid:
+ result.AppendError("unsupported format for writing memory");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+
+ case eFormatDefault:
+ case eFormatBytes:
+ case eFormatHex:
+ case eFormatHexUppercase:
+ case eFormatPointer:
+
+ // Decode hex bytes
+ uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (!UIntValueIsValidForSize (uval64, item_byte_size))
+ {
+ result.AppendErrorWithFormat ("Value 0x%" PRIx64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ buffer.PutMaxHex64 (uval64, item_byte_size);
+ break;
+
+ case eFormatBoolean:
+ uval64 = Args::StringToBoolean(value_str, false, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ buffer.PutMaxHex64 (uval64, item_byte_size);
+ break;
+
+ case eFormatBinary:
+ uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (!UIntValueIsValidForSize (uval64, item_byte_size))
+ {
+ result.AppendErrorWithFormat ("Value 0x%" PRIx64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ buffer.PutMaxHex64 (uval64, item_byte_size);
+ break;
+
+ case eFormatCharArray:
+ case eFormatChar:
+ case eFormatCString:
+ if (value_str[0])
+ {
+ size_t len = strlen (value_str);
+ // Include the NULL for C strings...
+ if (m_format_options.GetFormat() == eFormatCString)
+ ++len;
+ Error error;
+ if (process->WriteMemory (addr, value_str, len, error) == len)
+ {
+ addr += len;
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ break;
+
+ case eFormatDecimal:
+ sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (!SIntValueIsValidForSize (sval64, item_byte_size))
+ {
+ result.AppendErrorWithFormat ("Value %" PRIi64 " is too large or small to fit in a %lu byte signed integer value.\n", sval64, item_byte_size);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ buffer.PutMaxHex64 (sval64, item_byte_size);
+ break;
+
+ case eFormatUnsigned:
+ uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (!UIntValueIsValidForSize (uval64, item_byte_size))
+ {
+ result.AppendErrorWithFormat ("Value %" PRIu64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ buffer.PutMaxHex64 (uval64, item_byte_size);
+ break;
+
+ case eFormatOctal:
+ uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (!UIntValueIsValidForSize (uval64, item_byte_size))
+ {
+ result.AppendErrorWithFormat ("Value %" PRIo64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ buffer.PutMaxHex64 (uval64, item_byte_size);
+ break;
+ }
+ }
+
+ if (!buffer.GetString().empty())
+ {
+ Error error;
+ if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size())
+ return true;
+ else
+ {
+ result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupFormat m_format_options;
+ OptionGroupWriteMemory m_memory_options;
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectMemory
+//-------------------------------------------------------------------------
+
+CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "memory",
+ "A set of commands for operating on memory.",
+ "memory <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand ("read", CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
+ LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
+}
+
+CommandObjectMemory::~CommandObjectMemory ()
+{
+}
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectMemory.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectMemory.h
new file mode 100644
index 0000000..b044921
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectMemory.h
@@ -0,0 +1,33 @@
+//===-- CommandObjectMemory.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_CommandObjectMemory_h_
+#define liblldb_CommandObjectMemory_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+class CommandObjectMemory : public CommandObjectMultiword
+{
+public:
+ CommandObjectMemory (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMemory ();
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectMemory_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectMultiword.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectMultiword.cpp
new file mode 100644
index 0000000..f84b401
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectMultiword.cpp
@@ -0,0 +1,520 @@
+//===-- CommandObjectMultiword.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/CommandObjectMultiword.h"
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiword
+//-------------------------------------------------------------------------
+
+CommandObjectMultiword::CommandObjectMultiword
+(
+ CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t flags
+) :
+ CommandObject (interpreter, name, help, syntax, flags),
+ m_can_be_removed(false)
+{
+}
+
+CommandObjectMultiword::~CommandObjectMultiword ()
+{
+}
+
+CommandObjectSP
+CommandObjectMultiword::GetSubcommandSP (const char *sub_cmd, StringList *matches)
+{
+ CommandObjectSP return_cmd_sp;
+ CommandObject::CommandMap::iterator pos;
+
+ if (!m_subcommand_dict.empty())
+ {
+ pos = m_subcommand_dict.find (sub_cmd);
+ if (pos != m_subcommand_dict.end()) {
+ // An exact match; append the sub_cmd to the 'matches' string list.
+ if (matches)
+ matches->AppendString(sub_cmd);
+ return_cmd_sp = pos->second;
+ }
+ else
+ {
+
+ StringList local_matches;
+ if (matches == NULL)
+ matches = &local_matches;
+ int num_matches = CommandObject::AddNamesMatchingPartialString (m_subcommand_dict, sub_cmd, *matches);
+
+ if (num_matches == 1)
+ {
+ // Cleaner, but slightly less efficient would be to call back into this function, since I now
+ // know I have an exact match...
+
+ sub_cmd = matches->GetStringAtIndex(0);
+ pos = m_subcommand_dict.find(sub_cmd);
+ if (pos != m_subcommand_dict.end())
+ return_cmd_sp = pos->second;
+ }
+ }
+ }
+ return return_cmd_sp;
+}
+
+CommandObject *
+CommandObjectMultiword::GetSubcommandObject (const char *sub_cmd, StringList *matches)
+{
+ return GetSubcommandSP(sub_cmd, matches).get();
+}
+
+bool
+CommandObjectMultiword::LoadSubCommand
+(
+ const char *name,
+ const CommandObjectSP& cmd_obj
+)
+{
+ CommandMap::iterator pos;
+ bool success = true;
+
+ pos = m_subcommand_dict.find(name);
+ if (pos == m_subcommand_dict.end())
+ {
+ m_subcommand_dict[name] = cmd_obj;
+ }
+ else
+ success = false;
+
+ return success;
+}
+
+bool
+CommandObjectMultiword::Execute(const char *args_string, CommandReturnObject &result)
+{
+ Args args (args_string);
+ const size_t argc = args.GetArgumentCount();
+ if (argc == 0)
+ {
+ this->CommandObject::GenerateHelpText (result);
+ }
+ else
+ {
+ const char *sub_command = args.GetArgumentAtIndex (0);
+
+ if (sub_command)
+ {
+ if (::strcasecmp (sub_command, "help") == 0)
+ {
+ this->CommandObject::GenerateHelpText (result);
+ }
+ else if (!m_subcommand_dict.empty())
+ {
+ StringList matches;
+ CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);
+ if (sub_cmd_obj != NULL)
+ {
+ // Now call CommandObject::Execute to process and options in 'rest_of_line'. From there
+ // the command-specific version of Execute will be called, with the processed arguments.
+
+ args.Shift();
+
+ sub_cmd_obj->Execute (args_string, result);
+ }
+ else
+ {
+ std::string error_msg;
+ const size_t num_subcmd_matches = matches.GetSize();
+ if (num_subcmd_matches > 0)
+ error_msg.assign ("ambiguous command ");
+ else
+ error_msg.assign ("invalid command ");
+
+ error_msg.append ("'");
+ error_msg.append (GetCommandName());
+ error_msg.append (" ");
+ error_msg.append (sub_command);
+ error_msg.append ("'");
+
+ if (num_subcmd_matches > 0)
+ {
+ error_msg.append (" Possible completions:");
+ for (size_t i = 0; i < num_subcmd_matches; i++)
+ {
+ error_msg.append ("\n\t");
+ error_msg.append (matches.GetStringAtIndex (i));
+ }
+ }
+ error_msg.append ("\n");
+ result.AppendRawError (error_msg.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' does not have any subcommands.\n", GetCommandName());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+
+ return result.Succeeded();
+}
+
+void
+CommandObjectMultiword::GenerateHelpText (Stream &output_stream)
+{
+ // First time through here, generate the help text for the object and
+ // push it to the return result object as well
+
+ output_stream.PutCString ("The following subcommands are supported:\n\n");
+
+ CommandMap::iterator pos;
+ uint32_t max_len = m_interpreter.FindLongestCommandWord (m_subcommand_dict);
+
+ if (max_len)
+ max_len += 4; // Indent the output by 4 spaces.
+
+ for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos)
+ {
+ std::string indented_command (" ");
+ indented_command.append (pos->first);
+ if (pos->second->WantsRawCommandString ())
+ {
+ std::string help_text (pos->second->GetHelp());
+ help_text.append (" This command takes 'raw' input (no need to quote stuff).");
+ m_interpreter.OutputFormattedHelpText (output_stream,
+ indented_command.c_str(),
+ "--",
+ help_text.c_str(),
+ max_len);
+ }
+ else
+ m_interpreter.OutputFormattedHelpText (output_stream,
+ indented_command.c_str(),
+ "--",
+ pos->second->GetHelp(),
+ max_len);
+ }
+
+ output_stream.PutCString ("\nFor more help on any particular subcommand, type 'help <command> <subcommand>'.\n");
+}
+
+int
+CommandObjectMultiword::HandleCompletion
+(
+ Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches
+)
+{
+ // Any of the command matches will provide a complete word, otherwise the individual
+ // completers will override this.
+ word_complete = true;
+
+ if (cursor_index == 0)
+ {
+ CommandObject::AddNamesMatchingPartialString (m_subcommand_dict,
+ input.GetArgumentAtIndex(0),
+ matches);
+
+ if (matches.GetSize() == 1
+ && matches.GetStringAtIndex(0) != NULL
+ && strcmp (input.GetArgumentAtIndex(0), matches.GetStringAtIndex(0)) == 0)
+ {
+ StringList temp_matches;
+ CommandObject *cmd_obj = GetSubcommandObject (input.GetArgumentAtIndex(0),
+ &temp_matches);
+ if (cmd_obj != NULL)
+ {
+ matches.DeleteStringAtIndex (0);
+ input.Shift();
+ cursor_char_position = 0;
+ input.AppendArgument ("");
+ return cmd_obj->HandleCompletion (input,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ }
+ else
+ return matches.GetSize();
+ }
+ else
+ return matches.GetSize();
+ }
+ else
+ {
+ CommandObject *sub_command_object = GetSubcommandObject (input.GetArgumentAtIndex(0),
+ &matches);
+ if (sub_command_object == NULL)
+ {
+ return matches.GetSize();
+ }
+ else
+ {
+ // Remove the one match that we got from calling GetSubcommandObject.
+ matches.DeleteStringAtIndex(0);
+ input.Shift();
+ cursor_index--;
+ return sub_command_object->HandleCompletion (input,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ }
+
+ }
+}
+
+const char *
+CommandObjectMultiword::GetRepeatCommand (Args &current_command_args, uint32_t index)
+{
+ index++;
+ if (current_command_args.GetArgumentCount() <= index)
+ return NULL;
+ CommandObject *sub_command_object = GetSubcommandObject (current_command_args.GetArgumentAtIndex(index));
+ if (sub_command_object == NULL)
+ return NULL;
+ return sub_command_object->GetRepeatCommand(current_command_args, index);
+}
+
+
+void
+CommandObjectMultiword::AproposAllSubCommands (const char *prefix,
+ const char *search_word,
+ StringList &commands_found,
+ StringList &commands_help)
+{
+ CommandObject::CommandMap::const_iterator pos;
+
+ for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos)
+ {
+ const char * command_name = pos->first.c_str();
+ CommandObject *sub_cmd_obj = pos->second.get();
+ StreamString complete_command_name;
+
+ complete_command_name.Printf ("%s %s", prefix, command_name);
+
+ if (sub_cmd_obj->HelpTextContainsWord (search_word))
+ {
+ commands_found.AppendString (complete_command_name.GetData());
+ commands_help.AppendString (sub_cmd_obj->GetHelp());
+ }
+
+ if (sub_cmd_obj->IsMultiwordObject())
+ sub_cmd_obj->AproposAllSubCommands (complete_command_name.GetData(),
+ search_word,
+ commands_found,
+ commands_help);
+ }
+}
+
+
+
+CommandObjectProxy::CommandObjectProxy (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t flags) :
+ CommandObject (interpreter, name, help, syntax, flags)
+{
+}
+
+CommandObjectProxy::~CommandObjectProxy ()
+{
+}
+
+const char *
+CommandObjectProxy::GetHelpLong ()
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->GetHelpLong();
+ return NULL;
+}
+
+bool
+CommandObjectProxy::IsRemovable() const
+{
+ const CommandObject *proxy_command = const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->IsRemovable();
+ return false;
+}
+
+bool
+CommandObjectProxy::IsMultiwordObject ()
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->IsMultiwordObject();
+ return false;
+}
+
+lldb::CommandObjectSP
+CommandObjectProxy::GetSubcommandSP (const char *sub_cmd, StringList *matches)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->GetSubcommandSP(sub_cmd, matches);
+ return lldb::CommandObjectSP();
+}
+
+CommandObject *
+CommandObjectProxy::GetSubcommandObject (const char *sub_cmd, StringList *matches)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->GetSubcommandObject(sub_cmd, matches);
+ return NULL;
+}
+
+void
+CommandObjectProxy::AproposAllSubCommands (const char *prefix,
+ const char *search_word,
+ StringList &commands_found,
+ StringList &commands_help)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->AproposAllSubCommands (prefix,
+ search_word,
+ commands_found,
+ commands_help);
+}
+
+bool
+CommandObjectProxy::LoadSubCommand (const char *cmd_name,
+ const lldb::CommandObjectSP& command_sp)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->LoadSubCommand (cmd_name, command_sp);
+ return false;
+}
+
+bool
+CommandObjectProxy::WantsRawCommandString()
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->WantsRawCommandString();
+ return false;
+}
+
+bool
+CommandObjectProxy::WantsCompletion()
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->WantsCompletion();
+ return false;
+}
+
+
+Options *
+CommandObjectProxy::GetOptions ()
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->GetOptions ();
+ return NULL;
+}
+
+
+int
+CommandObjectProxy::HandleCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->HandleCompletion (input,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ matches.Clear();
+ return 0;
+}
+int
+CommandObjectProxy::HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->HandleArgumentCompletion (input,
+ cursor_index,
+ cursor_char_position,
+ opt_element_vector,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ matches.Clear();
+ return 0;
+}
+
+const char *
+CommandObjectProxy::GetRepeatCommand (Args &current_command_args,
+ uint32_t index)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->GetRepeatCommand (current_command_args, index);
+ return NULL;
+}
+
+bool
+CommandObjectProxy::Execute (const char *args_string,
+ CommandReturnObject &result)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->Execute (args_string, result);
+ result.AppendError ("command is not implemented");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlatform.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlatform.cpp
new file mode 100644
index 0000000..c2185e5
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlatform.cpp
@@ -0,0 +1,987 @@
+//===-- CommandObjectPlatform.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 "CommandObjectPlatform.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionGroupPlatform.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//----------------------------------------------------------------------
+// "platform select <platform-name>"
+//----------------------------------------------------------------------
+class CommandObjectPlatformSelect : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformSelect (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform select",
+ "Create a platform if needed and select it as the current platform.",
+ "platform select <platform-name>",
+ 0),
+ m_option_group (interpreter),
+ m_platform_options (false) // Don't include the "--platform" option by passing false
+ {
+ m_option_group.Append (&m_platform_options, LLDB_OPT_SET_ALL, 1);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectPlatformSelect ()
+ {
+ }
+
+ virtual int
+ HandleCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::PlatformPluginNames (m_interpreter,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ if (args.GetArgumentCount() == 1)
+ {
+ const char *platform_name = args.GetArgumentAtIndex (0);
+ if (platform_name && platform_name[0])
+ {
+ const bool select = true;
+ m_platform_options.SetPlatformName (platform_name);
+ Error error;
+ ArchSpec platform_arch;
+ PlatformSP platform_sp (m_platform_options.CreatePlatformWithOptions (m_interpreter, ArchSpec(), select, error, platform_arch));
+ if (platform_sp)
+ {
+ platform_sp->GetStatus (result.GetOutputStream());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid platform name");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("platform create takes a platform name as an argument\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupPlatform m_platform_options;
+};
+
+//----------------------------------------------------------------------
+// "platform list"
+//----------------------------------------------------------------------
+class CommandObjectPlatformList : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform list",
+ "List all platforms that are available.",
+ NULL,
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformList ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Stream &ostrm = result.GetOutputStream();
+ ostrm.Printf("Available platforms:\n");
+
+ PlatformSP host_platform_sp (Platform::GetDefaultPlatform());
+ ostrm.Printf ("%s: %s\n",
+ host_platform_sp->GetPluginName().GetCString(),
+ host_platform_sp->GetDescription());
+
+ uint32_t idx;
+ for (idx = 0; 1; ++idx)
+ {
+ const char *plugin_name = PluginManager::GetPlatformPluginNameAtIndex (idx);
+ if (plugin_name == NULL)
+ break;
+ const char *plugin_desc = PluginManager::GetPlatformPluginDescriptionAtIndex (idx);
+ if (plugin_desc == NULL)
+ break;
+ ostrm.Printf("%s: %s\n", plugin_name, plugin_desc);
+ }
+
+ if (idx == 0)
+ {
+ result.AppendError ("no platforms are available\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+};
+
+//----------------------------------------------------------------------
+// "platform status"
+//----------------------------------------------------------------------
+class CommandObjectPlatformStatus : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformStatus (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform status",
+ "Display status for the currently selected platform.",
+ NULL,
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformStatus ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Stream &ostrm = result.GetOutputStream();
+
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ PlatformSP platform_sp;
+ if (target)
+ {
+ platform_sp = target->GetPlatform();
+ }
+ if (!platform_sp)
+ {
+ platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
+ }
+ if (platform_sp)
+ {
+ platform_sp->GetStatus (ostrm);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError ("no platform us currently selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+//----------------------------------------------------------------------
+// "platform connect <connect-url>"
+//----------------------------------------------------------------------
+class CommandObjectPlatformConnect : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformConnect (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform connect",
+ "Connect a platform by name to be the currently selected platform.",
+ "platform connect <connect-url>",
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformConnect ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Stream &ostrm = result.GetOutputStream();
+
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ if (platform_sp)
+ {
+ Error error (platform_sp->ConnectRemote (args));
+ if (error.Success())
+ {
+ platform_sp->GetStatus (ostrm);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("%s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("no platform us currently selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+//----------------------------------------------------------------------
+// "platform disconnect"
+//----------------------------------------------------------------------
+class CommandObjectPlatformDisconnect : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformDisconnect (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform disconnect",
+ "Disconnect a platform by name to be the currently selected platform.",
+ "platform disconnect",
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformDisconnect ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ if (platform_sp)
+ {
+ if (args.GetArgumentCount() == 0)
+ {
+ Error error;
+
+ if (platform_sp->IsConnected())
+ {
+ // Cache the instance name if there is one since we are
+ // about to disconnect and the name might go with it.
+ const char *hostname_cstr = platform_sp->GetHostname();
+ std::string hostname;
+ if (hostname_cstr)
+ hostname.assign (hostname_cstr);
+
+ error = platform_sp->DisconnectRemote ();
+ if (error.Success())
+ {
+ Stream &ostrm = result.GetOutputStream();
+ if (hostname.empty())
+ ostrm.Printf ("Disconnected from \"%s\"\n", platform_sp->GetPluginName().GetCString());
+ else
+ ostrm.Printf ("Disconnected from \"%s\"\n", hostname.c_str());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("%s", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ // Not connected...
+ result.AppendErrorWithFormat ("not connected to '%s'", platform_sp->GetPluginName().GetCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ // Bad args
+ result.AppendError ("\"platform disconnect\" doesn't take any arguments");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("no platform is currently selected");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+//----------------------------------------------------------------------
+// "platform process launch"
+//----------------------------------------------------------------------
+class CommandObjectPlatformProcessLaunch : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformProcessLaunch (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform process launch",
+ "Launch a new process on a remote platform.",
+ "platform process launch program",
+ eFlagRequiresTarget | eFlagTryTargetAPILock),
+ m_options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformProcessLaunch ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ PlatformSP platform_sp;
+ if (target)
+ {
+ platform_sp = target->GetPlatform();
+ }
+ if (!platform_sp)
+ {
+ platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
+ }
+
+ if (platform_sp)
+ {
+ Error error;
+ const size_t argc = args.GetArgumentCount();
+ Target *target = m_exe_ctx.GetTargetPtr();
+ Module *exe_module = target->GetExecutableModulePointer();
+ if (exe_module)
+ {
+ m_options.launch_info.GetExecutableFile () = exe_module->GetFileSpec();
+ char exe_path[PATH_MAX];
+ if (m_options.launch_info.GetExecutableFile ().GetPath (exe_path, sizeof(exe_path)))
+ m_options.launch_info.GetArguments().AppendArgument (exe_path);
+ m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture();
+ }
+
+ if (argc > 0)
+ {
+ if (m_options.launch_info.GetExecutableFile ())
+ {
+ // We already have an executable file, so we will use this
+ // and all arguments to this function are extra arguments
+ m_options.launch_info.GetArguments().AppendArguments (args);
+ }
+ else
+ {
+ // We don't have any file yet, so the first argument is our
+ // executable, and the rest are program arguments
+ const bool first_arg_is_executable = true;
+ m_options.launch_info.SetArguments (args, first_arg_is_executable);
+ }
+ }
+
+ if (m_options.launch_info.GetExecutableFile ())
+ {
+ Debugger &debugger = m_interpreter.GetDebugger();
+
+ if (argc == 0)
+ target->GetRunArguments(m_options.launch_info.GetArguments());
+
+ ProcessSP process_sp (platform_sp->DebugProcess (m_options.launch_info,
+ debugger,
+ target,
+ debugger.GetListener(),
+ error));
+ if (process_sp && process_sp->IsAlive())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+ if (error.Success())
+ result.AppendError ("process launch failed");
+ else
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ result.AppendError ("'platform process launch' uses the current target file and arguments, or the executable and its arguments can be specified in this command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendError ("no platform is selected\n");
+ }
+ return result.Succeeded();
+ }
+
+protected:
+ ProcessLaunchCommandOptions m_options;
+};
+
+
+
+//----------------------------------------------------------------------
+// "platform process list"
+//----------------------------------------------------------------------
+class CommandObjectPlatformProcessList : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformProcessList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform process list",
+ "List processes on a remote platform by name, pid, or many other matching attributes.",
+ "platform process list",
+ 0),
+ m_options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformProcessList ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ PlatformSP platform_sp;
+ if (target)
+ {
+ platform_sp = target->GetPlatform();
+ }
+ if (!platform_sp)
+ {
+ platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
+ }
+
+ if (platform_sp)
+ {
+ Error error;
+ if (args.GetArgumentCount() == 0)
+ {
+
+ if (platform_sp)
+ {
+ Stream &ostrm = result.GetOutputStream();
+
+ lldb::pid_t pid = m_options.match_info.GetProcessInfo().GetProcessID();
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ ProcessInstanceInfo proc_info;
+ if (platform_sp->GetProcessInfo (pid, proc_info))
+ {
+ ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
+ proc_info.DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no process found with pid = %" PRIu64 "\n", pid);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ ProcessInstanceInfoList proc_infos;
+ const uint32_t matches = platform_sp->FindProcesses (m_options.match_info, proc_infos);
+ const char *match_desc = NULL;
+ const char *match_name = m_options.match_info.GetProcessInfo().GetName();
+ if (match_name && match_name[0])
+ {
+ switch (m_options.match_info.GetNameMatchType())
+ {
+ case eNameMatchIgnore: break;
+ case eNameMatchEquals: match_desc = "matched"; break;
+ case eNameMatchContains: match_desc = "contained"; break;
+ case eNameMatchStartsWith: match_desc = "started with"; break;
+ case eNameMatchEndsWith: match_desc = "ended with"; break;
+ case eNameMatchRegularExpression: match_desc = "matched the regular expression"; break;
+ }
+ }
+
+ if (matches == 0)
+ {
+ if (match_desc)
+ result.AppendErrorWithFormat ("no processes were found that %s \"%s\" on the \"%s\" platform\n",
+ match_desc,
+ match_name,
+ platform_sp->GetPluginName().GetCString());
+ else
+ result.AppendErrorWithFormat ("no processes were found on the \"%s\" platform\n", platform_sp->GetPluginName().GetCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ result.AppendMessageWithFormat ("%u matching process%s found on \"%s\"",
+ matches,
+ matches > 1 ? "es were" : " was",
+ platform_sp->GetName().GetCString());
+ if (match_desc)
+ result.AppendMessageWithFormat (" whose name %s \"%s\"",
+ match_desc,
+ match_name);
+ result.AppendMessageWithFormat ("\n");
+ ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
+ for (uint32_t i=0; i<matches; ++i)
+ {
+ proc_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid args: process list takes only options\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("no platform is selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ match_info ()
+ {
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+ bool success = false;
+
+ switch (short_option)
+ {
+ case 'p':
+ match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success));
+ if (!success)
+ error.SetErrorStringWithFormat("invalid process ID string: '%s'", option_arg);
+ break;
+
+ case 'P':
+ match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success));
+ if (!success)
+ error.SetErrorStringWithFormat("invalid parent process ID string: '%s'", option_arg);
+ break;
+
+ case 'u':
+ match_info.GetProcessInfo().SetUserID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
+ if (!success)
+ error.SetErrorStringWithFormat("invalid user ID string: '%s'", option_arg);
+ break;
+
+ case 'U':
+ match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
+ if (!success)
+ error.SetErrorStringWithFormat("invalid effective user ID string: '%s'", option_arg);
+ break;
+
+ case 'g':
+ match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
+ if (!success)
+ error.SetErrorStringWithFormat("invalid group ID string: '%s'", option_arg);
+ break;
+
+ case 'G':
+ match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
+ if (!success)
+ error.SetErrorStringWithFormat("invalid effective group ID string: '%s'", option_arg);
+ break;
+
+ case 'a':
+ match_info.GetProcessInfo().GetArchitecture().SetTriple (option_arg, m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform().get());
+ break;
+
+ case 'n':
+ match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
+ match_info.SetNameMatchType (eNameMatchEquals);
+ break;
+
+ case 'e':
+ match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
+ match_info.SetNameMatchType (eNameMatchEndsWith);
+ break;
+
+ case 's':
+ match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
+ match_info.SetNameMatchType (eNameMatchStartsWith);
+ break;
+
+ case 'c':
+ match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
+ match_info.SetNameMatchType (eNameMatchContains);
+ break;
+
+ case 'r':
+ match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
+ match_info.SetNameMatchType (eNameMatchRegularExpression);
+ break;
+
+ case 'A':
+ show_args = true;
+ break;
+
+ case 'v':
+ verbose = true;
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ match_info.Clear();
+ show_args = false;
+ verbose = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ ProcessInstanceInfoMatch match_info;
+ bool show_args;
+ bool verbose;
+ };
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectPlatformProcessList::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1 , false, "pid" , 'p', required_argument, NULL, 0, eArgTypePid , "List the process info for a specific process ID." },
+{ LLDB_OPT_SET_2 , true , "name" , 'n', required_argument, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that match a string." },
+{ LLDB_OPT_SET_3 , true , "ends-with" , 'e', required_argument, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that end with a string." },
+{ LLDB_OPT_SET_4 , true , "starts-with", 's', required_argument, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that start with a string." },
+{ LLDB_OPT_SET_5 , true , "contains" , 'c', required_argument, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that contain a string." },
+{ LLDB_OPT_SET_6 , true , "regex" , 'r', required_argument, NULL, 0, eArgTypeRegularExpression, "Find processes with executable basenames that match a regular expression." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "parent" , 'P', required_argument, NULL, 0, eArgTypePid , "Find processes that have a matching parent process ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "uid" , 'u', required_argument, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching user ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "euid" , 'U', required_argument, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching effective user ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "gid" , 'g', required_argument, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching group ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "egid" , 'G', required_argument, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching effective group ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "arch" , 'a', required_argument, NULL, 0, eArgTypeArchitecture , "Find processes that have a matching architecture." },
+{ LLDB_OPT_SET_FROM_TO(1, 6), false, "show-args" , 'A', no_argument , NULL, 0, eArgTypeNone , "Show process arguments instead of the process executable basename." },
+{ LLDB_OPT_SET_FROM_TO(1, 6), false, "verbose" , 'v', no_argument , NULL, 0, eArgTypeNone , "Enable verbose output." },
+{ 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone , NULL }
+};
+
+//----------------------------------------------------------------------
+// "platform process info"
+//----------------------------------------------------------------------
+class CommandObjectPlatformProcessInfo : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformProcessInfo (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform process info",
+ "Get detailed information for one or more process by process ID.",
+ "platform process info <pid> [<pid> <pid> ...]",
+ 0)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData pid_args;
+
+ // Define the first (and only) variant of this arg.
+ pid_args.arg_type = eArgTypePid;
+ pid_args.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (pid_args);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectPlatformProcessInfo ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ PlatformSP platform_sp;
+ if (target)
+ {
+ platform_sp = target->GetPlatform();
+ }
+ if (!platform_sp)
+ {
+ platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
+ }
+
+ if (platform_sp)
+ {
+ const size_t argc = args.GetArgumentCount();
+ if (argc > 0)
+ {
+ Error error;
+
+ if (platform_sp->IsConnected())
+ {
+ Stream &ostrm = result.GetOutputStream();
+ bool success;
+ for (size_t i=0; i<argc; ++ i)
+ {
+ const char *arg = args.GetArgumentAtIndex(i);
+ lldb::pid_t pid = Args::StringToUInt32 (arg, LLDB_INVALID_PROCESS_ID, 0, &success);
+ if (success)
+ {
+ ProcessInstanceInfo proc_info;
+ if (platform_sp->GetProcessInfo (pid, proc_info))
+ {
+ ostrm.Printf ("Process information for process %" PRIu64 ":\n", pid);
+ proc_info.Dump (ostrm, platform_sp.get());
+ }
+ else
+ {
+ ostrm.Printf ("error: no process information is available for process %" PRIu64 "\n", pid);
+ }
+ ostrm.EOL();
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("invalid process ID argument '%s'", arg);
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Not connected...
+ result.AppendErrorWithFormat ("not connected to '%s'", platform_sp->GetPluginName().GetCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ // No args
+ result.AppendError ("one or more process id(s) must be specified");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("no platform is currently selected");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+
+
+
+class CommandObjectPlatformProcess : public CommandObjectMultiword
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectPlatformProcess (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "platform process",
+ "A set of commands to query, launch and attach to platform processes",
+ "platform process [attach|launch|list] ...")
+ {
+// LoadSubCommand ("attach", CommandObjectSP (new CommandObjectPlatformProcessAttach (interpreter)));
+ LoadSubCommand ("launch", CommandObjectSP (new CommandObjectPlatformProcessLaunch (interpreter)));
+ LoadSubCommand ("info" , CommandObjectSP (new CommandObjectPlatformProcessInfo (interpreter)));
+ LoadSubCommand ("list" , CommandObjectSP (new CommandObjectPlatformProcessList (interpreter)));
+
+ }
+
+ virtual
+ ~CommandObjectPlatformProcess ()
+ {
+ }
+
+private:
+ //------------------------------------------------------------------
+ // For CommandObjectPlatform only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatformProcess);
+};
+
+
+class CommandObjectPlatformShell : public CommandObjectRaw
+{
+public:
+ CommandObjectPlatformShell (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "platform shell",
+ "Run a shell command on a the selected platform.",
+ "platform shell <shell-command>",
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformShell ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *raw_command_line, CommandReturnObject &result)
+ {
+ // TODO: Implement "Platform::RunShellCommand()" and switch over to using
+ // the current platform when it is in the interface.
+ const char *working_dir = NULL;
+ std::string output;
+ int status = -1;
+ int signo = -1;
+ Error error (Host::RunShellCommand (raw_command_line, working_dir, &status, &signo, &output, 10));
+ if (!output.empty())
+ result.GetOutputStream().PutCString(output.c_str());
+ if (status > 0)
+ {
+ if (signo > 0)
+ {
+ const char *signo_cstr = Host::GetSignalAsCString(signo);
+ if (signo_cstr)
+ result.GetOutputStream().Printf("error: command returned with status %i and signal %s\n", status, signo_cstr);
+ else
+ result.GetOutputStream().Printf("error: command returned with status %i and signal %i\n", status, signo);
+ }
+ else
+ result.GetOutputStream().Printf("error: command returned with status %i\n", status);
+ }
+
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ return true;
+ }
+};
+
+//----------------------------------------------------------------------
+// CommandObjectPlatform constructor
+//----------------------------------------------------------------------
+CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "platform",
+ "A set of commands to manage and create platforms.",
+ "platform [connect|disconnect|info|list|status|select] ...")
+{
+ LoadSubCommand ("select", CommandObjectSP (new CommandObjectPlatformSelect (interpreter)));
+ LoadSubCommand ("list" , CommandObjectSP (new CommandObjectPlatformList (interpreter)));
+ LoadSubCommand ("status", CommandObjectSP (new CommandObjectPlatformStatus (interpreter)));
+ LoadSubCommand ("connect", CommandObjectSP (new CommandObjectPlatformConnect (interpreter)));
+ LoadSubCommand ("disconnect", CommandObjectSP (new CommandObjectPlatformDisconnect (interpreter)));
+ LoadSubCommand ("process", CommandObjectSP (new CommandObjectPlatformProcess (interpreter)));
+ LoadSubCommand ("shell", CommandObjectSP (new CommandObjectPlatformShell (interpreter)));
+}
+
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CommandObjectPlatform::~CommandObjectPlatform()
+{
+}
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlatform.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlatform.h
new file mode 100644
index 0000000..f3bd758
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlatform.h
@@ -0,0 +1,40 @@
+//===-- CommandObjectPlatform.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_CommandObjectPlatform_h_
+#define liblldb_CommandObjectPlatform_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/Options.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectPlatform
+//-------------------------------------------------------------------------
+
+class CommandObjectPlatform : public CommandObjectMultiword
+{
+public:
+ CommandObjectPlatform(CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectPlatform();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatform);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectPlatform_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlugin.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlugin.cpp
new file mode 100644
index 0000000..1bc7632
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlugin.cpp
@@ -0,0 +1,122 @@
+//===-- CommandObjectPlugin.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 "CommandObjectPlugin.h"
+
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBCommandReturnObject.h"
+
+#include "lldb/Host/Host.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class CommandObjectPluginLoad : public CommandObjectParsed
+{
+private:
+public:
+ CommandObjectPluginLoad (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "plugin load",
+ "Import a dylib that implements an LLDB plugin.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentData cmd_arg;
+
+ // Define the first (and only) variant of this arg.
+ cmd_arg.arg_type = eArgTypeFilename;
+ cmd_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (cmd_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ }
+
+ ~CommandObjectPluginLoad ()
+ {
+ }
+
+ int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eDiskFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ typedef void (*LLDBCommandPluginInit) (lldb::SBDebugger debugger);
+
+ size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendError ("'plugin load' requires one argument");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char* path = command.GetArgumentAtIndex(0);
+
+ Error error;
+
+ FileSpec dylib_fspec(path,true);
+
+ if (m_interpreter.GetDebugger().LoadPlugin(dylib_fspec, error))
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ else
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+};
+
+CommandObjectPlugin::CommandObjectPlugin (CommandInterpreter &interpreter) :
+CommandObjectMultiword (interpreter,
+ "plugin",
+ "A set of commands for managing or customizing plugin commands.",
+ "plugin <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand ("load", CommandObjectSP (new CommandObjectPluginLoad (interpreter)));
+}
+
+CommandObjectPlugin::~CommandObjectPlugin ()
+{
+}
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlugin.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlugin.h
new file mode 100644
index 0000000..9d0f0fc
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlugin.h
@@ -0,0 +1,36 @@
+//===-- CommandObjectPlugin.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_CommandObjectPlugin_h_
+#define liblldb_CommandObjectPlugin_h_
+
+// C Includes
+// C++ Includes
+
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-types.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+ class CommandObjectPlugin : public CommandObjectMultiword
+ {
+ public:
+ CommandObjectPlugin (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectPlugin ();
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectPlugin_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.cpp
new file mode 100644
index 0000000..4c406a4
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.cpp
@@ -0,0 +1,1945 @@
+//===-- CommandObjectProcess.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 "CommandObjectProcess.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointSite.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class CommandObjectProcessLaunchOrAttach : public CommandObjectParsed
+{
+public:
+ CommandObjectProcessLaunchOrAttach (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t flags,
+ const char *new_process_action) :
+ CommandObjectParsed (interpreter, name, help, syntax, flags),
+ m_new_process_action (new_process_action) {}
+
+ virtual ~CommandObjectProcessLaunchOrAttach () {}
+protected:
+ bool
+ StopProcessIfNecessary (Process *&process, StateType &state, CommandReturnObject &result)
+ {
+ state = eStateInvalid;
+ if (process)
+ {
+ state = process->GetState();
+
+ if (process->IsAlive() && state != eStateConnected)
+ {
+ char message[1024];
+ if (process->GetState() == eStateAttaching)
+ ::snprintf (message, sizeof(message), "There is a pending attach, abort it and %s?", m_new_process_action.c_str());
+ else if (process->GetShouldDetach())
+ ::snprintf (message, sizeof(message), "There is a running process, detach from it and %s?", m_new_process_action.c_str());
+ else
+ ::snprintf (message, sizeof(message), "There is a running process, kill it and %s?", m_new_process_action.c_str());
+
+ if (!m_interpreter.Confirm (message, true))
+ {
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ if (process->GetShouldDetach())
+ {
+ bool keep_stopped = false;
+ Error detach_error (process->Detach(keep_stopped));
+ if (detach_error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ process = NULL;
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to detach from process: %s\n", detach_error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ Error destroy_error (process->Destroy());
+ if (destroy_error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ process = NULL;
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to kill process: %s\n", destroy_error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ }
+ }
+ return result.Succeeded();
+ }
+ std::string m_new_process_action;
+};
+//-------------------------------------------------------------------------
+// CommandObjectProcessLaunch
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessLaunch
+class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach
+{
+public:
+
+ CommandObjectProcessLaunch (CommandInterpreter &interpreter) :
+ CommandObjectProcessLaunchOrAttach (interpreter,
+ "process launch",
+ "Launch the executable in the debugger.",
+ NULL,
+ eFlagRequiresTarget,
+ "restart"),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData run_args_arg;
+
+ // Define the first (and only) variant of this arg.
+ run_args_arg.arg_type = eArgTypeRunArgs;
+ run_args_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (run_args_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ ~CommandObjectProcessLaunch ()
+ {
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eDiskFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ virtual const char *GetRepeatCommand (Args &current_command_args, uint32_t index)
+ {
+ // No repeat for "process launch"...
+ return "";
+ }
+
+protected:
+ bool
+ DoExecute (Args& launch_args, CommandReturnObject &result)
+ {
+ Debugger &debugger = m_interpreter.GetDebugger();
+ Target *target = debugger.GetSelectedTarget().get();
+ Error error;
+ // If our listener is NULL, users aren't allows to launch
+ char filename[PATH_MAX];
+ const Module *exe_module = target->GetExecutableModulePointer();
+
+ if (exe_module == NULL)
+ {
+ result.AppendError ("no file in target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ StateType state = eStateInvalid;
+ Process *process = m_exe_ctx.GetProcessPtr();
+
+ if (!StopProcessIfNecessary(process, state, result))
+ return false;
+
+ const char *target_settings_argv0 = target->GetArg0();
+
+ exe_module->GetFileSpec().GetPath (filename, sizeof(filename));
+
+ if (target_settings_argv0)
+ {
+ m_options.launch_info.GetArguments().AppendArgument (target_settings_argv0);
+ m_options.launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), false);
+ }
+ else
+ {
+ m_options.launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
+ }
+
+ if (launch_args.GetArgumentCount() == 0)
+ {
+ Args target_setting_args;
+ if (target->GetRunArguments(target_setting_args))
+ m_options.launch_info.GetArguments().AppendArguments (target_setting_args);
+ }
+ else
+ {
+ m_options.launch_info.GetArguments().AppendArguments (launch_args);
+
+ // Save the arguments for subsequent runs in the current target.
+ target->SetRunArguments (launch_args);
+ }
+
+ if (target->GetDisableASLR())
+ m_options.launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
+
+ if (target->GetDisableSTDIO())
+ m_options.launch_info.GetFlags().Set (eLaunchFlagDisableSTDIO);
+
+ m_options.launch_info.GetFlags().Set (eLaunchFlagDebug);
+
+ Args environment;
+ target->GetEnvironmentAsArgs (environment);
+ if (environment.GetArgumentCount() > 0)
+ m_options.launch_info.GetEnvironmentEntries ().AppendArguments (environment);
+
+ // Get the value of synchronous execution here. If you wait till after you have started to
+ // run, then you could have hit a breakpoint, whose command might switch the value, and
+ // then you'll pick up that incorrect value.
+ bool synchronous_execution = m_interpreter.GetSynchronous ();
+
+ // Finalize the file actions, and if none were given, default to opening
+ // up a pseudo terminal
+ const bool default_to_use_pty = true;
+ m_options.launch_info.FinalizeFileActions (target, default_to_use_pty);
+
+ if (state == eStateConnected)
+ {
+ if (m_options.launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY))
+ {
+ result.AppendWarning("can't launch in tty when launching through a remote connection");
+ m_options.launch_info.GetFlags().Clear (eLaunchFlagLaunchInTTY);
+ }
+ }
+
+ if (!m_options.launch_info.GetArchitecture().IsValid())
+ m_options.launch_info.GetArchitecture() = target->GetArchitecture();
+
+ PlatformSP platform_sp (target->GetPlatform());
+
+ if (platform_sp && platform_sp->CanDebugProcess ())
+ {
+ process = target->GetPlatform()->DebugProcess (m_options.launch_info,
+ debugger,
+ target,
+ debugger.GetListener(),
+ error).get();
+ }
+ else
+ {
+ const char *plugin_name = m_options.launch_info.GetProcessPluginName();
+ process = target->CreateProcess (debugger.GetListener(), plugin_name, NULL).get();
+ if (process)
+ error = process->Launch (m_options.launch_info);
+ }
+
+ if (process == NULL)
+ {
+ result.SetError (error, "failed to launch or debug process");
+ return false;
+ }
+
+
+ if (error.Success())
+ {
+ const char *archname = exe_module->GetArchitecture().GetArchitectureName();
+
+ result.AppendMessageWithFormat ("Process %" PRIu64 " launched: '%s' (%s)\n", process->GetID(), filename, archname);
+ result.SetDidChangeProcessState (true);
+ if (m_options.launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == false)
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ StateType state = process->WaitForProcessToStop (NULL);
+
+ if (state == eStateStopped)
+ {
+ error = process->Resume();
+ if (error.Success())
+ {
+ if (synchronous_execution)
+ {
+ state = process->WaitForProcessToStop (NULL);
+ const bool must_be_alive = true;
+ if (!StateIsStoppedState(state, must_be_alive))
+ {
+ result.AppendErrorWithFormat ("process isn't stopped: %s", StateAsCString(state));
+ }
+ result.SetDidChangeProcessState (true);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("process resume at entry point failed: %s", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("initial process state wasn't stopped: %s", StateAsCString(state));
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("process launch failed: %s", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+
+protected:
+ ProcessLaunchCommandOptions m_options;
+};
+
+
+//#define SET1 LLDB_OPT_SET_1
+//#define SET2 LLDB_OPT_SET_2
+//#define SET3 LLDB_OPT_SET_3
+//
+//OptionDefinition
+//CommandObjectProcessLaunch::CommandOptions::g_option_table[] =
+//{
+//{ SET1 | SET2 | SET3, false, "stop-at-entry", 's', no_argument, NULL, 0, eArgTypeNone, "Stop at the entry point of the program when launching a process."},
+//{ SET1 , false, "stdin", 'i', required_argument, NULL, 0, eArgTypeDirectoryName, "Redirect stdin for the process to <path>."},
+//{ SET1 , false, "stdout", 'o', required_argument, NULL, 0, eArgTypeDirectoryName, "Redirect stdout for the process to <path>."},
+//{ SET1 , false, "stderr", 'e', required_argument, NULL, 0, eArgTypeDirectoryName, "Redirect stderr for the process to <path>."},
+//{ SET1 | SET2 | SET3, false, "plugin", 'p', required_argument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
+//{ SET2 , false, "tty", 't', optional_argument, NULL, 0, eArgTypeDirectoryName, "Start the process in a terminal. If <path> is specified, look for a terminal whose name contains <path>, else start the process in a new terminal."},
+//{ SET3, false, "no-stdio", 'n', no_argument, NULL, 0, eArgTypeNone, "Do not set up for terminal I/O to go to running process."},
+//{ SET1 | SET2 | SET3, false, "working-dir", 'w', required_argument, NULL, 0, eArgTypeDirectoryName, "Set the current working directory to <path> when running the inferior."},
+//{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+//};
+//
+//#undef SET1
+//#undef SET2
+//#undef SET3
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessAttach
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessAttach
+class CommandObjectProcessAttach : public CommandObjectProcessLaunchOrAttach
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ // Keep default values of all options in one place: OptionParsingStarting ()
+ OptionParsingStarting ();
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+ bool success = false;
+ switch (short_option)
+ {
+ case 'c':
+ attach_info.SetContinueOnceAttached(true);
+ break;
+
+ case 'p':
+ {
+ lldb::pid_t pid = Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success);
+ if (!success || pid == LLDB_INVALID_PROCESS_ID)
+ {
+ error.SetErrorStringWithFormat("invalid process ID '%s'", option_arg);
+ }
+ else
+ {
+ attach_info.SetProcessID (pid);
+ }
+ }
+ break;
+
+ case 'P':
+ attach_info.SetProcessPluginName (option_arg);
+ break;
+
+ case 'n':
+ attach_info.GetExecutableFile().SetFile(option_arg, false);
+ break;
+
+ case 'w':
+ attach_info.SetWaitForLaunch(true);
+ break;
+
+ case 'i':
+ attach_info.SetIgnoreExisting(false);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ attach_info.Clear();
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ virtual bool
+ 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,
+ StringList &matches)
+ {
+ 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;
+
+ // We are only completing the name option for now...
+
+ const OptionDefinition *opt_defs = GetDefinitions();
+ if (opt_defs[opt_defs_index].short_option == 'n')
+ {
+ // Are we in the name?
+
+ // Look to see if there is a -P argument provided, and if so use that plugin, otherwise
+ // use the default plugin.
+
+ const char *partial_name = NULL;
+ partial_name = input.GetArgumentAtIndex(opt_arg_pos);
+
+ PlatformSP platform_sp (m_interpreter.GetPlatform (true));
+ if (platform_sp)
+ {
+ ProcessInstanceInfoList process_infos;
+ ProcessInstanceInfoMatch match_info;
+ if (partial_name)
+ {
+ match_info.GetProcessInfo().GetExecutableFile().SetFile(partial_name, false);
+ match_info.SetNameMatchType(eNameMatchStartsWith);
+ }
+ platform_sp->FindProcesses (match_info, process_infos);
+ const size_t num_matches = process_infos.GetSize();
+ if (num_matches > 0)
+ {
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ matches.AppendString (process_infos.GetProcessNameAtIndex(i),
+ process_infos.GetProcessNameLengthAtIndex(i));
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ ProcessAttachInfo attach_info;
+ };
+
+ CommandObjectProcessAttach (CommandInterpreter &interpreter) :
+ CommandObjectProcessLaunchOrAttach (interpreter,
+ "process attach",
+ "Attach to a process.",
+ "process attach <cmd-options>",
+ 0,
+ "attach"),
+ m_options (interpreter)
+ {
+ }
+
+ ~CommandObjectProcessAttach ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ // N.B. The attach should be synchronous. It doesn't help much to get the prompt back between initiating the attach
+ // and the target actually stopping. So even if the interpreter is set to be asynchronous, we wait for the stop
+ // ourselves here.
+
+ StateType state = eStateInvalid;
+ Process *process = m_exe_ctx.GetProcessPtr();
+
+ if (!StopProcessIfNecessary (process, state, result))
+ return false;
+
+ if (target == NULL)
+ {
+ // If there isn't a current target create one.
+ TargetSP new_target_sp;
+ Error error;
+
+ error = m_interpreter.GetDebugger().GetTargetList().CreateTarget (m_interpreter.GetDebugger(),
+ NULL,
+ NULL,
+ false,
+ NULL, // No platform options
+ new_target_sp);
+ target = new_target_sp.get();
+ if (target == NULL || error.Fail())
+ {
+ result.AppendError(error.AsCString("Error creating target"));
+ return false;
+ }
+ m_interpreter.GetDebugger().GetTargetList().SetSelectedTarget(target);
+ }
+
+ // Record the old executable module, we want to issue a warning if the process of attaching changed the
+ // current executable (like somebody said "file foo" then attached to a PID whose executable was bar.)
+
+ ModuleSP old_exec_module_sp = target->GetExecutableModule();
+ ArchSpec old_arch_spec = target->GetArchitecture();
+
+ if (command.GetArgumentCount())
+ {
+ result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ if (state != eStateConnected)
+ {
+ const char *plugin_name = m_options.attach_info.GetProcessPluginName();
+ process = target->CreateProcess (m_interpreter.GetDebugger().GetListener(), plugin_name, NULL).get();
+ }
+
+ if (process)
+ {
+ Error error;
+ // If no process info was specified, then use the target executable
+ // name as the process to attach to by default
+ if (!m_options.attach_info.ProcessInfoSpecified ())
+ {
+ if (old_exec_module_sp)
+ m_options.attach_info.GetExecutableFile().GetFilename() = old_exec_module_sp->GetPlatformFileSpec().GetFilename();
+
+ if (!m_options.attach_info.ProcessInfoSpecified ())
+ {
+ error.SetErrorString ("no process specified, create a target with a file, or specify the --pid or --name command option");
+ }
+ }
+
+ if (error.Success())
+ {
+ error = process->Attach (m_options.attach_info);
+
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("attach failed: %s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ // If we're synchronous, wait for the stopped event and report that.
+ // Otherwise just return.
+ // FIXME: in the async case it will now be possible to get to the command
+ // interpreter with a state eStateAttaching. Make sure we handle that correctly.
+ StateType state = process->WaitForProcessToStop (NULL);
+
+ result.SetDidChangeProcessState (true);
+
+ if (state == eStateStopped)
+ {
+ result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("attach failed: process did not stop (no such process or permission problem?)");
+ process->Destroy();
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ }
+
+ if (result.Succeeded())
+ {
+ // Okay, we're done. Last step is to warn if the executable module has changed:
+ char new_path[PATH_MAX];
+ ModuleSP new_exec_module_sp (target->GetExecutableModule());
+ if (!old_exec_module_sp)
+ {
+ // We might not have a module if we attached to a raw pid...
+ if (new_exec_module_sp)
+ {
+ new_exec_module_sp->GetFileSpec().GetPath(new_path, PATH_MAX);
+ result.AppendMessageWithFormat("Executable module set to \"%s\".\n", new_path);
+ }
+ }
+ else if (old_exec_module_sp->GetFileSpec() != new_exec_module_sp->GetFileSpec())
+ {
+ char old_path[PATH_MAX];
+
+ old_exec_module_sp->GetFileSpec().GetPath (old_path, PATH_MAX);
+ new_exec_module_sp->GetFileSpec().GetPath (new_path, PATH_MAX);
+
+ result.AppendWarningWithFormat("Executable module changed from \"%s\" to \"%s\".\n",
+ old_path, new_path);
+ }
+
+ if (!old_arch_spec.IsValid())
+ {
+ result.AppendMessageWithFormat ("Architecture set to: %s.\n", target->GetArchitecture().GetTriple().getTriple().c_str());
+ }
+ else if (!old_arch_spec.IsExactMatch(target->GetArchitecture()))
+ {
+ result.AppendWarningWithFormat("Architecture changed from %s to %s.\n",
+ old_arch_spec.GetTriple().getTriple().c_str(),
+ target->GetArchitecture().GetTriple().getTriple().c_str());
+ }
+
+ // This supports the use-case scenario of immediately continuing the process once attached.
+ if (m_options.attach_info.GetContinueOnceAttached())
+ m_interpreter.HandleCommand("process continue", eLazyBoolNo, result);
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+
+OptionDefinition
+CommandObjectProcessAttach::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "continue",'c', no_argument, NULL, 0, eArgTypeNone, "Immediately continue the process once attached."},
+{ LLDB_OPT_SET_ALL, false, "plugin", 'P', required_argument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
+{ LLDB_OPT_SET_1, false, "pid", 'p', required_argument, NULL, 0, eArgTypePid, "The process ID of an existing process to attach to."},
+{ LLDB_OPT_SET_2, false, "name", 'n', required_argument, NULL, 0, eArgTypeProcessName, "The name of the process to attach to."},
+{ LLDB_OPT_SET_2, false, "include-existing", 'i', no_argument, NULL, 0, eArgTypeNone, "Include existing processes when doing attach -w."},
+{ LLDB_OPT_SET_2, false, "waitfor", 'w', no_argument, NULL, 0, eArgTypeNone, "Wait for the process with <process-name> to launch."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessContinue
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessContinue
+
+class CommandObjectProcessContinue : public CommandObjectParsed
+{
+public:
+
+ CommandObjectProcessContinue (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process continue",
+ "Continue execution of all threads in the current process.",
+ "process continue",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_options(interpreter)
+ {
+ }
+
+
+ ~CommandObjectProcessContinue ()
+ {
+ }
+
+protected:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ // Keep default values of all options in one place: OptionParsingStarting ()
+ OptionParsingStarting ();
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+ bool success = false;
+ switch (short_option)
+ {
+ case 'i':
+ m_ignore = Args::StringToUInt32 (option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("invalid value for ignore option: \"%s\", should be a number.", option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_ignore = 0;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ uint32_t m_ignore;
+ };
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ bool synchronous_execution = m_interpreter.GetSynchronous ();
+ StateType state = process->GetState();
+ if (state == eStateStopped)
+ {
+ if (command.GetArgumentCount() != 0)
+ {
+ result.AppendErrorWithFormat ("The '%s' command does not take any arguments.\n", m_cmd_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_ignore > 0)
+ {
+ ThreadSP sel_thread_sp(process->GetThreadList().GetSelectedThread());
+ if (sel_thread_sp)
+ {
+ StopInfoSP stop_info_sp = sel_thread_sp->GetStopInfo();
+ if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint)
+ {
+ lldb::break_id_t bp_site_id = (lldb::break_id_t)stop_info_sp->GetValue();
+ BreakpointSiteSP bp_site_sp(process->GetBreakpointSiteList().FindByID(bp_site_id));
+ if (bp_site_sp)
+ {
+ const size_t num_owners = bp_site_sp->GetNumberOfOwners();
+ for (size_t i = 0; i < num_owners; i++)
+ {
+ Breakpoint &bp_ref = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
+ if (!bp_ref.IsInternal())
+ {
+ bp_ref.SetIgnoreCount(m_options.m_ignore);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ { // Scope for thread list mutex:
+ Mutex::Locker locker (process->GetThreadList().GetMutex());
+ const uint32_t num_threads = process->GetThreadList().GetSize();
+
+ // Set the actions that the threads should each take when resuming
+ for (uint32_t idx=0; idx<num_threads; ++idx)
+ {
+ process->GetThreadList().GetThreadAtIndex(idx)->SetResumeState (eStateRunning);
+ }
+ }
+
+ Error error(process->Resume());
+ if (error.Success())
+ {
+ result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
+ if (synchronous_execution)
+ {
+ state = process->WaitForProcessToStop (NULL);
+
+ result.SetDidChangeProcessState (true);
+ result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Process cannot be continued from its current state (%s).\n",
+ StateAsCString(state));
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ CommandOptions m_options;
+
+};
+
+OptionDefinition
+CommandObjectProcessContinue::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "ignore-count",'i', required_argument, NULL, 0, eArgTypeUnsignedInteger,
+ "Ignore <N> crossings of the breakpoint (if it exists) for the currently selected thread."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessDetach
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessDetach
+
+class CommandObjectProcessDetach : public CommandObjectParsed
+{
+public:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ OptionParsingStarting ();
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 's':
+ bool tmp_result;
+ bool success;
+ tmp_result = Args::StringToBoolean(option_arg, false, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid boolean option: \"%s\"", option_arg);
+ else
+ {
+ if (tmp_result)
+ m_keep_stopped = eLazyBoolYes;
+ else
+ m_keep_stopped = eLazyBoolNo;
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_keep_stopped = eLazyBoolCalculate;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ LazyBool m_keep_stopped;
+ };
+
+ CommandObjectProcessDetach (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process detach",
+ "Detach from the current process being debugged.",
+ "process detach",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched),
+ m_options(interpreter)
+ {
+ }
+
+ ~CommandObjectProcessDetach ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ result.AppendMessageWithFormat ("Detaching from process %" PRIu64 "\n", process->GetID());
+ // FIXME: This will be a Command Option:
+ bool keep_stopped;
+ if (m_options.m_keep_stopped == eLazyBoolCalculate)
+ {
+ // Check the process default:
+ if (process->GetDetachKeepsStopped())
+ keep_stopped = true;
+ else
+ keep_stopped = false;
+ }
+ else if (m_options.m_keep_stopped == eLazyBoolYes)
+ keep_stopped = true;
+ else
+ keep_stopped = false;
+
+ Error error (process->Detach(keep_stopped));
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Detach failed: %s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectProcessDetach::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "keep-stopped", 's', required_argument, NULL, 0, eArgTypeBoolean, "Whether or not the process should be kept stopped on detach (if possible)." },
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessConnect
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessConnect
+
+class CommandObjectProcessConnect : public CommandObjectParsed
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ // Keep default values of all options in one place: OptionParsingStarting ()
+ OptionParsingStarting ();
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'p':
+ plugin_name.assign (option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ plugin_name.clear();
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ std::string plugin_name;
+ };
+
+ CommandObjectProcessConnect (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process connect",
+ "Connect to a remote debug service.",
+ "process connect <remote-url>",
+ 0),
+ m_options (interpreter)
+ {
+ }
+
+ ~CommandObjectProcessConnect ()
+ {
+ }
+
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+
+ TargetSP target_sp (m_interpreter.GetDebugger().GetSelectedTarget());
+ Error error;
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ if (process->IsAlive())
+ {
+ result.AppendErrorWithFormat ("Process %" PRIu64 " is currently being debugged, kill the process before connecting.\n",
+ process->GetID());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ if (!target_sp)
+ {
+ // If there isn't a current target create one.
+
+ error = m_interpreter.GetDebugger().GetTargetList().CreateTarget (m_interpreter.GetDebugger(),
+ NULL,
+ NULL,
+ false,
+ NULL, // No platform options
+ target_sp);
+ if (!target_sp || error.Fail())
+ {
+ result.AppendError(error.AsCString("Error creating target"));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ m_interpreter.GetDebugger().GetTargetList().SetSelectedTarget(target_sp.get());
+ }
+
+ if (command.GetArgumentCount() == 1)
+ {
+ const char *plugin_name = NULL;
+ if (!m_options.plugin_name.empty())
+ plugin_name = m_options.plugin_name.c_str();
+
+ const char *remote_url = command.GetArgumentAtIndex(0);
+ process = target_sp->CreateProcess (m_interpreter.GetDebugger().GetListener(), plugin_name, NULL).get();
+
+ if (process)
+ {
+ error = process->ConnectRemote (&process->GetTarget().GetDebugger().GetOutputStream(), remote_url);
+
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString("Remote connect failed"));
+ result.SetStatus (eReturnStatusFailed);
+ target_sp->DeleteCurrentProcess();
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Unable to find process plug-in for remote URL '%s'.\nPlease specify a process plug-in name with the --plugin option, or specify an object file using the \"file\" command.\n",
+ remote_url);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' takes exactly one argument:\nUsage: %s\n",
+ m_cmd_name.c_str(),
+ m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectProcessConnect::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "plugin", 'p', required_argument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
+ { 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessPlugin
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessPlugin
+
+class CommandObjectProcessPlugin : public CommandObjectProxy
+{
+public:
+
+ CommandObjectProcessPlugin (CommandInterpreter &interpreter) :
+ CommandObjectProxy (interpreter,
+ "process plugin",
+ "Send a custom command to the current process plug-in.",
+ "process plugin <args>",
+ 0)
+ {
+ }
+
+ ~CommandObjectProcessPlugin ()
+ {
+ }
+
+ virtual CommandObject *
+ GetProxyCommandObject()
+ {
+ Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ return process->GetPluginCommandObject();
+ return NULL;
+ }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessLoad
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessLoad
+
+class CommandObjectProcessLoad : public CommandObjectParsed
+{
+public:
+
+ CommandObjectProcessLoad (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process load",
+ "Load a shared library into the current process.",
+ "process load <filename> [<filename> ...]",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused )
+ {
+ }
+
+ ~CommandObjectProcessLoad ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+
+ const size_t argc = command.GetArgumentCount();
+
+ for (uint32_t i=0; i<argc; ++i)
+ {
+ Error error;
+ const char *image_path = command.GetArgumentAtIndex(i);
+ FileSpec image_spec (image_path, false);
+ process->GetTarget().GetPlatform()->ResolveRemotePath(image_spec, image_spec);
+ uint32_t image_token = process->LoadImage(image_spec, error);
+ if (image_token != LLDB_INVALID_IMAGE_TOKEN)
+ {
+ result.AppendMessageWithFormat ("Loading \"%s\"...ok\nImage %u loaded.\n", image_path, image_token);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("failed to load '%s': %s", image_path, error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessUnload
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessUnload
+
+class CommandObjectProcessUnload : public CommandObjectParsed
+{
+public:
+
+ CommandObjectProcessUnload (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process unload",
+ "Unload a shared library from the current process using the index returned by a previous call to \"process load\".",
+ "process unload <index>",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused )
+ {
+ }
+
+ ~CommandObjectProcessUnload ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+
+ const size_t argc = command.GetArgumentCount();
+
+ for (uint32_t i=0; i<argc; ++i)
+ {
+ const char *image_token_cstr = command.GetArgumentAtIndex(i);
+ uint32_t image_token = Args::StringToUInt32(image_token_cstr, LLDB_INVALID_IMAGE_TOKEN, 0);
+ if (image_token == LLDB_INVALID_IMAGE_TOKEN)
+ {
+ result.AppendErrorWithFormat ("invalid image index argument '%s'", image_token_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ else
+ {
+ Error error (process->UnloadImage(image_token));
+ if (error.Success())
+ {
+ result.AppendMessageWithFormat ("Unloading shared library with index %u...ok\n", image_token);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("failed to unload image: %s", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessSignal
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessSignal
+
+class CommandObjectProcessSignal : public CommandObjectParsed
+{
+public:
+
+ CommandObjectProcessSignal (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process signal",
+ "Send a UNIX signal to the current process being debugged.",
+ NULL,
+ eFlagRequiresProcess | eFlagTryTargetAPILock)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData signal_arg;
+
+ // Define the first (and only) variant of this arg.
+ signal_arg.arg_type = eArgTypeUnixSignal;
+ signal_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (signal_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectProcessSignal ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+
+ if (command.GetArgumentCount() == 1)
+ {
+ int signo = LLDB_INVALID_SIGNAL_NUMBER;
+
+ const char *signal_name = command.GetArgumentAtIndex(0);
+ if (::isxdigit (signal_name[0]))
+ signo = Args::StringToSInt32(signal_name, LLDB_INVALID_SIGNAL_NUMBER, 0);
+ else
+ signo = process->GetUnixSignals().GetSignalNumberFromName (signal_name);
+
+ if (signo == LLDB_INVALID_SIGNAL_NUMBER)
+ {
+ result.AppendErrorWithFormat ("Invalid signal argument '%s'.\n", command.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ Error error (process->Signal (signo));
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to send signal %i: %s\n", signo, error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("'%s' takes exactly one signal number argument:\nUsage: %s\n", m_cmd_name.c_str(),
+ m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessInterrupt
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessInterrupt
+
+class CommandObjectProcessInterrupt : public CommandObjectParsed
+{
+public:
+
+
+ CommandObjectProcessInterrupt (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process interrupt",
+ "Interrupt the current process being debugged.",
+ "process interrupt",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched)
+ {
+ }
+
+ ~CommandObjectProcessInterrupt ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ {
+ result.AppendError ("no process to halt");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ bool clear_thread_plans = true;
+ Error error(process->Halt (clear_thread_plans));
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to halt process: %s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: %s\n",
+ m_cmd_name.c_str(),
+ m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessKill
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessKill
+
+class CommandObjectProcessKill : public CommandObjectParsed
+{
+public:
+
+ CommandObjectProcessKill (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process kill",
+ "Terminate the current process being debugged.",
+ "process kill",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched)
+ {
+ }
+
+ ~CommandObjectProcessKill ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ {
+ result.AppendError ("no process to kill");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ Error error (process->Destroy());
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to kill process: %s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: %s\n",
+ m_cmd_name.c_str(),
+ m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessStatus
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessStatus
+
+class CommandObjectProcessStatus : public CommandObjectParsed
+{
+public:
+ CommandObjectProcessStatus (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process status",
+ "Show the current status and location of executing process.",
+ "process status",
+ eFlagRequiresProcess | eFlagTryTargetAPILock)
+ {
+ }
+
+ ~CommandObjectProcessStatus()
+ {
+ }
+
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Stream &strm = result.GetOutputStream();
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
+ Process *process = m_exe_ctx.GetProcessPtr();
+ const bool only_threads_with_stop_reason = true;
+ const uint32_t start_frame = 0;
+ const uint32_t num_frames = 1;
+ const uint32_t num_frames_with_source = 1;
+ process->GetStatus(strm);
+ process->GetThreadStatus (strm,
+ only_threads_with_stop_reason,
+ start_frame,
+ num_frames,
+ num_frames_with_source);
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessHandle
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessHandle
+
+class CommandObjectProcessHandle : public CommandObjectParsed
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ OptionParsingStarting ();
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 's':
+ stop = option_arg;
+ break;
+ case 'n':
+ notify = option_arg;
+ break;
+ case 'p':
+ pass = option_arg;
+ break;
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ stop.clear();
+ notify.clear();
+ pass.clear();
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ std::string stop;
+ std::string notify;
+ std::string pass;
+ };
+
+
+ CommandObjectProcessHandle (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process handle",
+ "Show or update what the process and debugger should do with various signals received from the OS.",
+ NULL),
+ m_options (interpreter)
+ {
+ SetHelpLong ("If no signals are specified, update them all. If no update option is specified, list the current values.\n");
+ CommandArgumentEntry arg;
+ CommandArgumentData signal_arg;
+
+ signal_arg.arg_type = eArgTypeUnixSignal;
+ signal_arg.arg_repetition = eArgRepeatStar;
+
+ arg.push_back (signal_arg);
+
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectProcessHandle ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ bool
+ VerifyCommandOptionValue (const std::string &option, int &real_value)
+ {
+ bool okay = true;
+
+ bool success = false;
+ bool tmp_value = Args::StringToBoolean (option.c_str(), false, &success);
+
+ if (success && tmp_value)
+ real_value = 1;
+ else if (success && !tmp_value)
+ real_value = 0;
+ else
+ {
+ // If the value isn't 'true' or 'false', it had better be 0 or 1.
+ real_value = Args::StringToUInt32 (option.c_str(), 3);
+ if (real_value != 0 && real_value != 1)
+ okay = false;
+ }
+
+ return okay;
+ }
+
+ void
+ PrintSignalHeader (Stream &str)
+ {
+ str.Printf ("NAME PASS STOP NOTIFY\n");
+ str.Printf ("========== ===== ===== ======\n");
+ }
+
+ void
+ PrintSignal (Stream &str, int32_t signo, const char *sig_name, UnixSignals &signals)
+ {
+ bool stop;
+ bool suppress;
+ bool notify;
+
+ str.Printf ("%-10s ", sig_name);
+ if (signals.GetSignalInfo (signo, suppress, stop, notify))
+ {
+ bool pass = !suppress;
+ str.Printf ("%s %s %s",
+ (pass ? "true " : "false"),
+ (stop ? "true " : "false"),
+ (notify ? "true " : "false"));
+ }
+ str.Printf ("\n");
+ }
+
+ void
+ PrintSignalInformation (Stream &str, Args &signal_args, int num_valid_signals, UnixSignals &signals)
+ {
+ PrintSignalHeader (str);
+
+ if (num_valid_signals > 0)
+ {
+ size_t num_args = signal_args.GetArgumentCount();
+ for (size_t i = 0; i < num_args; ++i)
+ {
+ int32_t signo = signals.GetSignalNumberFromName (signal_args.GetArgumentAtIndex (i));
+ if (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ PrintSignal (str, signo, signal_args.GetArgumentAtIndex (i), signals);
+ }
+ }
+ else // Print info for ALL signals
+ {
+ int32_t signo = signals.GetFirstSignalNumber();
+ while (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ {
+ PrintSignal (str, signo, signals.GetSignalAsCString (signo), signals);
+ signo = signals.GetNextSignalNumber (signo);
+ }
+ }
+ }
+
+protected:
+ bool
+ DoExecute (Args &signal_args, CommandReturnObject &result)
+ {
+ TargetSP target_sp = m_interpreter.GetDebugger().GetSelectedTarget();
+
+ if (!target_sp)
+ {
+ result.AppendError ("No current target;"
+ " cannot handle signals until you have a valid target and process.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ProcessSP process_sp = target_sp->GetProcessSP();
+
+ if (!process_sp)
+ {
+ result.AppendError ("No current process; cannot handle signals until you have a valid process.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ int stop_action = -1; // -1 means leave the current setting alone
+ int pass_action = -1; // -1 means leave the current setting alone
+ int notify_action = -1; // -1 means leave the current setting alone
+
+ if (! m_options.stop.empty()
+ && ! VerifyCommandOptionValue (m_options.stop, stop_action))
+ {
+ result.AppendError ("Invalid argument for command option --stop; must be true or false.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (! m_options.notify.empty()
+ && ! VerifyCommandOptionValue (m_options.notify, notify_action))
+ {
+ result.AppendError ("Invalid argument for command option --notify; must be true or false.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (! m_options.pass.empty()
+ && ! VerifyCommandOptionValue (m_options.pass, pass_action))
+ {
+ result.AppendError ("Invalid argument for command option --pass; must be true or false.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ size_t num_args = signal_args.GetArgumentCount();
+ UnixSignals &signals = process_sp->GetUnixSignals();
+ int num_signals_set = 0;
+
+ if (num_args > 0)
+ {
+ for (size_t i = 0; i < num_args; ++i)
+ {
+ int32_t signo = signals.GetSignalNumberFromName (signal_args.GetArgumentAtIndex (i));
+ if (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ {
+ // Casting the actions as bools here should be okay, because VerifyCommandOptionValue guarantees
+ // the value is either 0 or 1.
+ if (stop_action != -1)
+ signals.SetShouldStop (signo, (bool) stop_action);
+ if (pass_action != -1)
+ {
+ bool suppress = ! ((bool) pass_action);
+ signals.SetShouldSuppress (signo, suppress);
+ }
+ if (notify_action != -1)
+ signals.SetShouldNotify (signo, (bool) notify_action);
+ ++num_signals_set;
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid signal name '%s'\n", signal_args.GetArgumentAtIndex (i));
+ }
+ }
+ }
+ else
+ {
+ // No signal specified, if any command options were specified, update ALL signals.
+ if ((notify_action != -1) || (stop_action != -1) || (pass_action != -1))
+ {
+ if (m_interpreter.Confirm ("Do you really want to update all the signals?", false))
+ {
+ int32_t signo = signals.GetFirstSignalNumber();
+ while (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ {
+ if (notify_action != -1)
+ signals.SetShouldNotify (signo, (bool) notify_action);
+ if (stop_action != -1)
+ signals.SetShouldStop (signo, (bool) stop_action);
+ if (pass_action != -1)
+ {
+ bool suppress = ! ((bool) pass_action);
+ signals.SetShouldSuppress (signo, suppress);
+ }
+ signo = signals.GetNextSignalNumber (signo);
+ }
+ }
+ }
+ }
+
+ PrintSignalInformation (result.GetOutputStream(), signal_args, num_signals_set, signals);
+
+ if (num_signals_set > 0)
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ else
+ result.SetStatus (eReturnStatusFailed);
+
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectProcessHandle::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "stop", 's', required_argument, NULL, 0, eArgTypeBoolean, "Whether or not the process should be stopped if the signal is received." },
+{ LLDB_OPT_SET_1, false, "notify", 'n', required_argument, NULL, 0, eArgTypeBoolean, "Whether or not the debugger should notify the user if the signal is received." },
+{ LLDB_OPT_SET_1, false, "pass", 'p', required_argument, NULL, 0, eArgTypeBoolean, "Whether or not the signal should be passed to the process." },
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordProcess
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordProcess::CommandObjectMultiwordProcess (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "process",
+ "A set of commands for operating on a process.",
+ "process <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand ("attach", CommandObjectSP (new CommandObjectProcessAttach (interpreter)));
+ LoadSubCommand ("launch", CommandObjectSP (new CommandObjectProcessLaunch (interpreter)));
+ LoadSubCommand ("continue", CommandObjectSP (new CommandObjectProcessContinue (interpreter)));
+ LoadSubCommand ("connect", CommandObjectSP (new CommandObjectProcessConnect (interpreter)));
+ LoadSubCommand ("detach", CommandObjectSP (new CommandObjectProcessDetach (interpreter)));
+ LoadSubCommand ("load", CommandObjectSP (new CommandObjectProcessLoad (interpreter)));
+ LoadSubCommand ("unload", CommandObjectSP (new CommandObjectProcessUnload (interpreter)));
+ LoadSubCommand ("signal", CommandObjectSP (new CommandObjectProcessSignal (interpreter)));
+ LoadSubCommand ("handle", CommandObjectSP (new CommandObjectProcessHandle (interpreter)));
+ LoadSubCommand ("status", CommandObjectSP (new CommandObjectProcessStatus (interpreter)));
+ LoadSubCommand ("interrupt", CommandObjectSP (new CommandObjectProcessInterrupt (interpreter)));
+ LoadSubCommand ("kill", CommandObjectSP (new CommandObjectProcessKill (interpreter)));
+ LoadSubCommand ("plugin", CommandObjectSP (new CommandObjectProcessPlugin (interpreter)));
+}
+
+CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess ()
+{
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.h
new file mode 100644
index 0000000..0aaa74d
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.h
@@ -0,0 +1,37 @@
+//===-- CommandObjectProcess.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_CommandObjectProcess_h_
+#define liblldb_CommandObjectProcess_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordProcess
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordProcess : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordProcess (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordProcess ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectProcess_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectQuit.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectQuit.cpp
new file mode 100644
index 0000000..d04ecdd
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectQuit.cpp
@@ -0,0 +1,99 @@
+//===-- CommandObjectQuit.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 "CommandObjectQuit.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;
+
+//-------------------------------------------------------------------------
+// CommandObjectQuit
+//-------------------------------------------------------------------------
+
+CommandObjectQuit::CommandObjectQuit (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter, "quit", "Quit out of the LLDB debugger.", "quit")
+{
+}
+
+CommandObjectQuit::~CommandObjectQuit ()
+{
+}
+
+// returns true if there is at least one alive process
+// is_a_detach will be true if all alive processes will be detached when you quit
+// and false if at least one process will be killed instead
+bool
+CommandObjectQuit::ShouldAskForConfirmation (bool& is_a_detach)
+{
+ if (m_interpreter.GetPromptOnQuit() == false)
+ return false;
+ bool should_prompt = false;
+ is_a_detach = true;
+ for (uint32_t debugger_idx = 0;
+ debugger_idx < Debugger::GetNumDebuggers();
+ debugger_idx++)
+ {
+ DebuggerSP debugger_sp(Debugger::GetDebuggerAtIndex(debugger_idx));
+ if (!debugger_sp)
+ continue;
+ const TargetList& target_list(debugger_sp->GetTargetList());
+ for (uint32_t target_idx = 0;
+ target_idx < target_list.GetNumTargets();
+ target_idx++)
+ {
+ TargetSP target_sp(target_list.GetTargetAtIndex(target_idx));
+ if (!target_sp)
+ continue;
+ ProcessSP process_sp(target_sp->GetProcessSP());
+ if (process_sp
+ && process_sp->IsValid()
+ && process_sp->IsAlive()
+ && process_sp->WarnBeforeDetach())
+ {
+ should_prompt = true;
+ if (process_sp->GetShouldDetach() == false)
+ {
+ // if we need to kill at least one process, just say so and return
+ is_a_detach = false;
+ return should_prompt;
+ }
+ }
+ }
+ }
+ return should_prompt;
+}
+
+bool
+CommandObjectQuit::DoExecute (Args& command, CommandReturnObject &result)
+{
+ bool is_a_detach = true;
+ if (ShouldAskForConfirmation (is_a_detach))
+ {
+ StreamString message;
+ message.Printf("Quitting LLDB will %s one or more processes. Do you really want to proceed", (is_a_detach ? "detach from" : "kill"));
+ if (!m_interpreter.Confirm(message.GetData(), true))
+ {
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ m_interpreter.BroadcastEvent (CommandInterpreter::eBroadcastBitQuitCommandReceived);
+ result.SetStatus (eReturnStatusQuit);
+ return true;
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectQuit.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectQuit.h
new file mode 100644
index 0000000..aab0e26
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectQuit.h
@@ -0,0 +1,46 @@
+//===-- CommandObjectQuit.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_CommandObjectQuit_h_
+#define liblldb_CommandObjectQuit_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectQuit
+//-------------------------------------------------------------------------
+
+class CommandObjectQuit : public CommandObjectParsed
+{
+public:
+
+ CommandObjectQuit (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectQuit ();
+
+protected:
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result);
+
+ bool
+ ShouldAskForConfirmation (bool& is_a_detach);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectQuit_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp
new file mode 100644
index 0000000..ba43f23
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp
@@ -0,0 +1,499 @@
+//===-- CommandObjectRegister.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 "CommandObjectRegister.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Interpreter/OptionValueArray.h"
+#include "lldb/Interpreter/OptionValueUInt64.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// "register read"
+//----------------------------------------------------------------------
+class CommandObjectRegisterRead : public CommandObjectParsed
+{
+public:
+ CommandObjectRegisterRead (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "register read",
+ "Dump the contents of one or more register values from the current frame. If no register is specified, dumps them all.",
+ NULL,
+ eFlagRequiresFrame |
+ eFlagRequiresRegContext |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_option_group (interpreter),
+ m_format_options (eFormatDefault),
+ m_command_options ()
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData register_arg;
+
+ // Define the first (and only) variant of this arg.
+ register_arg.arg_type = eArgTypeRegisterName;
+ register_arg.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (register_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+ // Add the "--format"
+ m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_ALL);
+ m_option_group.Append (&m_command_options);
+ m_option_group.Finalize();
+
+ }
+
+ virtual
+ ~CommandObjectRegisterRead ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+ bool
+ DumpRegister (const ExecutionContext &exe_ctx,
+ Stream &strm,
+ RegisterContext *reg_ctx,
+ const RegisterInfo *reg_info)
+ {
+ if (reg_info)
+ {
+ RegisterValue reg_value;
+
+ if (reg_ctx->ReadRegister (reg_info, reg_value))
+ {
+ strm.Indent ();
+
+ bool prefix_with_altname = m_command_options.alternate_name;
+ bool prefix_with_name = !prefix_with_altname;
+ reg_value.Dump(&strm, reg_info, prefix_with_name, prefix_with_altname, m_format_options.GetFormat(), 8);
+ if ((reg_info->encoding == eEncodingUint) || (reg_info->encoding == eEncodingSint))
+ {
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process && reg_info->byte_size == process->GetAddressByteSize())
+ {
+ addr_t reg_addr = reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS);
+ if (reg_addr != LLDB_INVALID_ADDRESS)
+ {
+ Address so_reg_addr;
+ if (exe_ctx.GetTargetRef().GetSectionLoadList().ResolveLoadAddress(reg_addr, so_reg_addr))
+ {
+ strm.PutCString (" ");
+ so_reg_addr.Dump(&strm, exe_ctx.GetBestExecutionContextScope(), Address::DumpStyleResolvedDescription);
+ }
+ }
+ }
+ }
+ strm.EOL();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool
+ DumpRegisterSet (const ExecutionContext &exe_ctx,
+ Stream &strm,
+ RegisterContext *reg_ctx,
+ size_t set_idx,
+ bool primitive_only=false)
+ {
+ uint32_t unavailable_count = 0;
+ uint32_t available_count = 0;
+
+ if (!reg_ctx)
+ return false; // thread has no registers (i.e. core files are corrupt, incomplete crash logs...)
+
+ const RegisterSet * const reg_set = reg_ctx->GetRegisterSet(set_idx);
+ if (reg_set)
+ {
+ strm.Printf ("%s:\n", reg_set->name);
+ strm.IndentMore ();
+ const size_t num_registers = reg_set->num_registers;
+ for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx)
+ {
+ const uint32_t reg = reg_set->registers[reg_idx];
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg);
+ // Skip the dumping of derived register if primitive_only is true.
+ if (primitive_only && reg_info && reg_info->value_regs)
+ continue;
+
+ if (DumpRegister (exe_ctx, strm, reg_ctx, reg_info))
+ ++available_count;
+ else
+ ++unavailable_count;
+ }
+ strm.IndentLess ();
+ if (unavailable_count)
+ {
+ strm.Indent ();
+ strm.Printf("%u registers were unavailable.\n", unavailable_count);
+ }
+ strm.EOL();
+ }
+ return available_count > 0;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Stream &strm = result.GetOutputStream();
+ RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext ();
+
+ const RegisterInfo *reg_info = NULL;
+ if (command.GetArgumentCount() == 0)
+ {
+ size_t set_idx;
+
+ size_t num_register_sets = 1;
+ const size_t set_array_size = m_command_options.set_indexes.GetSize();
+ if (set_array_size > 0)
+ {
+ for (size_t i=0; i<set_array_size; ++i)
+ {
+ set_idx = m_command_options.set_indexes[i]->GetUInt64Value (UINT32_MAX, NULL);
+ if (set_idx < reg_ctx->GetRegisterSetCount())
+ {
+ if (!DumpRegisterSet (m_exe_ctx, strm, reg_ctx, set_idx))
+ {
+ if (errno)
+ result.AppendErrorWithFormat ("register read failed with errno: %d\n", errno);
+ else
+ result.AppendError ("unknown error while reading registers.\n");
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("invalid register set index: %zu\n", set_idx);
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (m_command_options.dump_all_sets)
+ num_register_sets = reg_ctx->GetRegisterSetCount();
+
+ for (set_idx = 0; set_idx < num_register_sets; ++set_idx)
+ {
+ // When dump_all_sets option is set, dump primitive as well as derived registers.
+ DumpRegisterSet (m_exe_ctx, strm, reg_ctx, set_idx, !m_command_options.dump_all_sets.GetCurrentValue());
+ }
+ }
+ }
+ else
+ {
+ if (m_command_options.dump_all_sets)
+ {
+ result.AppendError ("the --all option can't be used when registers names are supplied as arguments\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else if (m_command_options.set_indexes.GetSize() > 0)
+ {
+ result.AppendError ("the --set <set> option can't be used when registers names are supplied as arguments\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ const char *arg_cstr;
+ for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx)
+ {
+ // in most LLDB commands we accept $rbx as the name for register RBX - and here we would
+ // reject it and non-existant. we should be more consistent towards the user and allow them
+ // to say reg read $rbx - internally, however, we should be strict and not allow ourselves
+ // to call our registers $rbx in our own API
+ if (*arg_cstr == '$')
+ arg_cstr = arg_cstr+1;
+ reg_info = reg_ctx->GetRegisterInfoByName(arg_cstr);
+
+ if (reg_info)
+ {
+ if (!DumpRegister (m_exe_ctx, strm, reg_ctx, reg_info))
+ strm.Printf("%-12s = error: unavailable\n", reg_info->name);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid register name '%s'.\n", arg_cstr);
+ }
+ }
+ }
+ }
+ return result.Succeeded();
+ }
+
+ class CommandOptions : public OptionGroup
+ {
+ public:
+ CommandOptions () :
+ OptionGroup(),
+ set_indexes (OptionValue::ConvertTypeToMask (OptionValue::eTypeUInt64)),
+ dump_all_sets (false, false), // Initial and default values are false
+ alternate_name (false, false)
+ {
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter)
+ {
+ set_indexes.Clear();
+ dump_all_sets.Clear();
+ alternate_name.Clear();
+ }
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value)
+ {
+ Error error;
+ const int short_option = g_option_table[option_idx].short_option;
+ switch (short_option)
+ {
+ case 's':
+ {
+ OptionValueSP value_sp (OptionValueUInt64::Create (option_value, error));
+ if (value_sp)
+ set_indexes.AppendValue (value_sp);
+ }
+ break;
+
+ case 'a':
+ // When we don't use OptionValue::SetValueFromCString(const char *) to
+ // set an option value, it won't be marked as being set in the options
+ // so we make a call to let users know the value was set via option
+ dump_all_sets.SetCurrentValue (true);
+ dump_all_sets.SetOptionWasSet ();
+ break;
+
+ case 'A':
+ // When we don't use OptionValue::SetValueFromCString(const char *) to
+ // set an option value, it won't be marked as being set in the options
+ // so we make a call to let users know the value was set via option
+ alternate_name.SetCurrentValue (true);
+ dump_all_sets.SetOptionWasSet ();
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static const OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ OptionValueArray set_indexes;
+ OptionValueBoolean dump_all_sets;
+ OptionValueBoolean alternate_name;
+ };
+
+ OptionGroupOptions m_option_group;
+ OptionGroupFormat m_format_options;
+ CommandOptions m_command_options;
+};
+
+const OptionDefinition
+CommandObjectRegisterRead::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "alternate", 'A', no_argument , NULL, 0, eArgTypeNone , "Display register names using the alternate register name if there is one."},
+ { LLDB_OPT_SET_1 , false, "set" , 's', required_argument, NULL, 0, eArgTypeIndex , "Specify which register sets to dump by index."},
+ { LLDB_OPT_SET_2 , false, "all" , 'a', no_argument , NULL, 0, eArgTypeNone , "Show all register sets."},
+};
+
+uint32_t
+CommandObjectRegisterRead::CommandOptions::GetNumDefinitions ()
+{
+ return sizeof(g_option_table)/sizeof(OptionDefinition);
+}
+
+
+//----------------------------------------------------------------------
+// "register write"
+//----------------------------------------------------------------------
+class CommandObjectRegisterWrite : public CommandObjectParsed
+{
+public:
+ CommandObjectRegisterWrite (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "register write",
+ "Modify a single register value.",
+ NULL,
+ eFlagRequiresFrame |
+ eFlagRequiresRegContext |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData register_arg;
+ CommandArgumentData value_arg;
+
+ // Define the first (and only) variant of this arg.
+ register_arg.arg_type = eArgTypeRegisterName;
+ register_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (register_arg);
+
+ // Define the first (and only) variant of this arg.
+ value_arg.arg_type = eArgTypeValue;
+ value_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (value_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ }
+
+ virtual
+ ~CommandObjectRegisterWrite ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute(Args& command, CommandReturnObject &result)
+ {
+ DataExtractor reg_data;
+ RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext ();
+
+ if (command.GetArgumentCount() != 2)
+ {
+ result.AppendError ("register write takes exactly 2 arguments: <reg-name> <value>");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ const char *reg_name = command.GetArgumentAtIndex(0);
+ const char *value_str = command.GetArgumentAtIndex(1);
+
+
+ // in most LLDB commands we accept $rbx as the name for register RBX - and here we would
+ // reject it and non-existant. we should be more consistent towards the user and allow them
+ // to say reg write $rbx - internally, however, we should be strict and not allow ourselves
+ // to call our registers $rbx in our own API
+ if (reg_name && *reg_name == '$')
+ reg_name = reg_name+1;
+
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
+
+ if (reg_info)
+ {
+ RegisterValue reg_value;
+
+ Error error (reg_value.SetValueFromCString (reg_info, value_str));
+ if (error.Success())
+ {
+ if (reg_ctx->WriteRegister (reg_info, reg_value))
+ {
+ // Toss all frames and anything else in the thread
+ // after a register has been written.
+ m_exe_ctx.GetThreadRef().Flush();
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+ }
+ if (error.AsCString())
+ {
+ result.AppendErrorWithFormat ("Failed to write register '%s' with value '%s': %s\n",
+ reg_name,
+ value_str,
+ error.AsCString());
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to write register '%s' with value '%s'",
+ reg_name,
+ value_str);
+ }
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Register not found for '%s'.\n", reg_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+
+//----------------------------------------------------------------------
+// CommandObjectRegister constructor
+//----------------------------------------------------------------------
+CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "register",
+ "A set of commands to access thread registers.",
+ "register [read|write] ...")
+{
+ LoadSubCommand ("read", CommandObjectSP (new CommandObjectRegisterRead (interpreter)));
+ LoadSubCommand ("write", CommandObjectSP (new CommandObjectRegisterWrite (interpreter)));
+}
+
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CommandObjectRegister::~CommandObjectRegister()
+{
+}
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.h
new file mode 100644
index 0000000..7f856c2
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.h
@@ -0,0 +1,45 @@
+//===-- CommandObjectRegister.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_CommandObjectRegister_h_
+#define liblldb_CommandObjectRegister_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectRegister
+//-------------------------------------------------------------------------
+
+class CommandObjectRegister : public CommandObjectMultiword
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectRegister(CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectRegister();
+
+private:
+ //------------------------------------------------------------------
+ // For CommandObjectRegister only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectRegister);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectRegister_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectSettings.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSettings.cpp
new file mode 100644
index 0000000..95cc9b6
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSettings.cpp
@@ -0,0 +1,1208 @@
+//===-- CommandObjectSettings.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 "CommandObjectSettings.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+
+using namespace lldb;
+using namespace lldb_private;
+#include "llvm/ADT/StringRef.h"
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsSet
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsSet : public CommandObjectRaw
+{
+public:
+ CommandObjectSettingsSet (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "settings set",
+ "Set or change the value of a single debugger setting variable.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData var_name_arg;
+ CommandArgumentData value_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (var_name_arg);
+
+ // Define the first (and only) variant of this arg.
+ value_arg.arg_type = eArgTypeValue;
+ value_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (value_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+
+ SetHelpLong (
+"When setting a dictionary or array variable, you can set multiple entries \n\
+at once by giving the values to the set command. For example: \n\
+\n\
+(lldb) settings set target.run-args value1 value2 value3 \n\
+(lldb) settings set target.env-vars MYPATH=~/.:/usr/bin SOME_ENV_VAR=12345 \n\
+\n\
+(lldb) settings show target.run-args \n\
+ [0]: 'value1' \n\
+ [1]: 'value2' \n\
+ [3]: 'value3' \n\
+(lldb) settings show target.env-vars \n\
+ 'MYPATH=~/.:/usr/bin'\n\
+ 'SOME_ENV_VAR=12345' \n\
+\n\
+Warning: The 'set' command re-sets the entire array or dictionary. If you \n\
+just want to add, remove or update individual values (or add something to \n\
+the end), use one of the other settings sub-commands: append, replace, \n\
+insert-before or insert-after.\n");
+
+ }
+
+
+ virtual
+ ~CommandObjectSettingsSet () {}
+
+ // Overrides base class's behavior where WantsCompletion = !WantsRawCommandString.
+ virtual bool
+ WantsCompletion() { return true; }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_global (false)
+ {
+ }
+
+ virtual
+ ~CommandOptions () {}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'g':
+ m_global = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized options '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_global = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_global;
+ };
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ const size_t argc = input.GetArgumentCount();
+ const char *arg = NULL;
+ int setting_var_idx;
+ for (setting_var_idx = 1; setting_var_idx < argc; ++setting_var_idx)
+ {
+ arg = input.GetArgumentAtIndex(setting_var_idx);
+ if (arg && arg[0] != '-')
+ break; // We found our setting variable name index
+ }
+ if (cursor_index == setting_var_idx)
+ {
+ // Attempting to complete setting variable name
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ }
+ else
+ {
+ arg = input.GetArgumentAtIndex(cursor_index);
+
+ if (arg)
+ {
+ if (arg[0] == '-')
+ {
+ // Complete option name
+ }
+ else
+ {
+ // Complete setting value
+ const char *setting_var_name = input.GetArgumentAtIndex(setting_var_idx);
+ Error error;
+ lldb::OptionValueSP value_sp (m_interpreter.GetDebugger().GetPropertyValue(&m_exe_ctx, setting_var_name, false, error));
+ if (value_sp)
+ {
+ value_sp->AutoComplete (m_interpreter,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ }
+ }
+ }
+ }
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result)
+ {
+ Args cmd_args(command);
+
+ // Process possible options.
+ if (!ParseOptions (cmd_args, result))
+ return false;
+
+ const size_t argc = cmd_args.GetArgumentCount ();
+ if ((argc < 2) && (!m_options.m_global))
+ {
+ result.AppendError ("'settings set' takes more arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *var_name = cmd_args.GetArgumentAtIndex (0);
+ if ((var_name == NULL) || (var_name[0] == '\0'))
+ {
+ result.AppendError ("'settings set' command requires a valid variable name");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Split the raw command into var_name and value pair.
+ llvm::StringRef raw_str(command);
+ std::string var_value_string = raw_str.split(var_name).second.str();
+ const char *var_value_cstr = Args::StripSpaces(var_value_string, true, true, false);
+
+ Error error;
+ if (m_options.m_global)
+ {
+ error = m_interpreter.GetDebugger().SetPropertyValue (NULL,
+ eVarSetOperationAssign,
+ var_name,
+ var_value_cstr);
+ }
+
+ if (error.Success())
+ {
+ // FIXME this is the same issue as the one in commands script import
+ // we could be setting target.load-script-from-symbol-file which would cause
+ // Python scripts to be loaded, which could run LLDB commands
+ // (e.g. settings set target.process.python-os-plugin-path) and cause a crash
+ // if we did not clear the command's exe_ctx first
+ ExecutionContext exe_ctx(m_exe_ctx);
+ m_exe_ctx.Clear();
+ error = m_interpreter.GetDebugger().SetPropertyValue (&exe_ctx,
+ eVarSetOperationAssign,
+ var_name,
+ var_value_cstr);
+ }
+
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+
+ return result.Succeeded();
+ }
+private:
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectSettingsSet::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_2, false, "global", 'g', no_argument, NULL, 0, eArgTypeNone, "Apply the new value to the global default value." },
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsShow -- Show current values
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsShow : public CommandObjectParsed
+{
+public:
+ CommandObjectSettingsShow (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "settings show",
+ "Show the specified internal debugger setting variable and its value, or show all the currently set variables and their values, if nothing is specified.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentData var_name_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (var_name_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ }
+
+ virtual
+ ~CommandObjectSettingsShow () {}
+
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+
+ const size_t argc = args.GetArgumentCount ();
+ if (argc > 0)
+ {
+ for (size_t i=0; i<argc; ++i)
+ {
+ const char *property_path = args.GetArgumentAtIndex (i);
+
+ Error error(m_interpreter.GetDebugger().DumpPropertyValue (&m_exe_ctx, result.GetOutputStream(), property_path, OptionValue::eDumpGroupValue));
+ if (error.Success())
+ {
+ result.GetOutputStream().EOL();
+ }
+ else
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ m_interpreter.GetDebugger().DumpAllPropertyValues (&m_exe_ctx, result.GetOutputStream(), OptionValue::eDumpGroupValue);
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsList -- List settable variables
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsList : public CommandObjectParsed
+{
+public:
+ CommandObjectSettingsList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "settings list",
+ "List and describe all the internal debugger settings variables that are available to the user to 'set' or 'show', or describe a particular variable or set of variables (by specifying the variable name or a common prefix).",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData var_name_arg;
+ CommandArgumentData prefix_name_arg;
+
+ // Define the first variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatOptional;
+
+ // Define the second variant of this arg.
+ prefix_name_arg.arg_type = eArgTypeSettingPrefix;
+ prefix_name_arg.arg_repetition = eArgRepeatOptional;
+
+ arg.push_back (var_name_arg);
+ arg.push_back (prefix_name_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectSettingsList () {}
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+
+ const bool will_modify = false;
+ const size_t argc = args.GetArgumentCount ();
+ if (argc > 0)
+ {
+ const bool dump_qualified_name = true;
+
+ for (size_t i=0; i<argc; ++i)
+ {
+ const char *property_path = args.GetArgumentAtIndex (i);
+
+ const Property *property = m_interpreter.GetDebugger().GetValueProperties()->GetPropertyAtPath (&m_exe_ctx, will_modify, property_path);
+
+ if (property)
+ {
+ property->DumpDescription (m_interpreter, result.GetOutputStream(), 0, dump_qualified_name);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("invalid property path '%s'", property_path);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ m_interpreter.GetDebugger().DumpAllDescriptions (m_interpreter, result.GetOutputStream());
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsRemove
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsRemove : public CommandObjectRaw
+{
+public:
+ CommandObjectSettingsRemove (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "settings remove",
+ "Remove the specified element from an array or dictionary settings variable.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData var_name_arg;
+ CommandArgumentData index_arg;
+ CommandArgumentData key_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (var_name_arg);
+
+ // Define the first variant of this arg.
+ index_arg.arg_type = eArgTypeSettingIndex;
+ index_arg.arg_repetition = eArgRepeatPlain;
+
+ // Define the second variant of this arg.
+ key_arg.arg_type = eArgTypeSettingKey;
+ key_arg.arg_repetition = eArgRepeatPlain;
+
+ // Push both variants into this arg
+ arg2.push_back (index_arg);
+ arg2.push_back (key_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ }
+
+ virtual
+ ~CommandObjectSettingsRemove () {}
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ // Attempting to complete variable name
+ if (cursor_index < 2)
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+
+ Args cmd_args(command);
+
+ // Process possible options.
+ if (!ParseOptions (cmd_args, result))
+ return false;
+
+ const size_t argc = cmd_args.GetArgumentCount ();
+ if (argc == 0)
+ {
+ result.AppendError ("'settings set' takes an array or dictionary item, or an array followed by one or more indexes, or a dictionary followed by one or more key names to remove");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *var_name = cmd_args.GetArgumentAtIndex (0);
+ if ((var_name == NULL) || (var_name[0] == '\0'))
+ {
+ result.AppendError ("'settings set' command requires a valid variable name");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Split the raw command into var_name and value pair.
+ llvm::StringRef raw_str(command);
+ std::string var_value_string = raw_str.split(var_name).second.str();
+ const char *var_value_cstr = Args::StripSpaces(var_value_string, true, true, false);
+
+ Error error (m_interpreter.GetDebugger().SetPropertyValue (&m_exe_ctx,
+ eVarSetOperationRemove,
+ var_name,
+ var_value_cstr));
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsReplace
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsReplace : public CommandObjectRaw
+{
+public:
+ CommandObjectSettingsReplace (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "settings replace",
+ "Replace the specified element from an internal debugger settings array or dictionary variable with the specified new value.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentEntry arg3;
+ CommandArgumentData var_name_arg;
+ CommandArgumentData index_arg;
+ CommandArgumentData key_arg;
+ CommandArgumentData value_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (var_name_arg);
+
+ // Define the first (variant of this arg.
+ index_arg.arg_type = eArgTypeSettingIndex;
+ index_arg.arg_repetition = eArgRepeatPlain;
+
+ // Define the second (variant of this arg.
+ key_arg.arg_type = eArgTypeSettingKey;
+ key_arg.arg_repetition = eArgRepeatPlain;
+
+ // Put both variants into this arg
+ arg2.push_back (index_arg);
+ arg2.push_back (key_arg);
+
+ // Define the first (and only) variant of this arg.
+ value_arg.arg_type = eArgTypeValue;
+ value_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg3.push_back (value_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ m_arguments.push_back (arg3);
+ }
+
+
+ virtual
+ ~CommandObjectSettingsReplace () {}
+
+ // Overrides base class's behavior where WantsCompletion = !WantsRawCommandString.
+ virtual bool
+ WantsCompletion() { return true; }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ // Attempting to complete variable name
+ if (cursor_index < 2)
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+
+ Args cmd_args(command);
+ const char *var_name = cmd_args.GetArgumentAtIndex (0);
+ if ((var_name == NULL) || (var_name[0] == '\0'))
+ {
+ result.AppendError ("'settings replace' command requires a valid variable name; No value supplied");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+
+ // Split the raw command into var_name, index_value, and value triple.
+ llvm::StringRef raw_str(command);
+ std::string var_value_string = raw_str.split(var_name).second.str();
+ const char *var_value_cstr = Args::StripSpaces(var_value_string, true, true, false);
+
+ Error error(m_interpreter.GetDebugger().SetPropertyValue (&m_exe_ctx,
+ eVarSetOperationReplace,
+ var_name,
+ var_value_cstr));
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsInsertBefore
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsInsertBefore : public CommandObjectRaw
+{
+public:
+ CommandObjectSettingsInsertBefore (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "settings insert-before",
+ "Insert value(s) into an internal debugger settings array variable, immediately before the specified element.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentEntry arg3;
+ CommandArgumentData var_name_arg;
+ CommandArgumentData index_arg;
+ CommandArgumentData value_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (var_name_arg);
+
+ // Define the first (variant of this arg.
+ index_arg.arg_type = eArgTypeSettingIndex;
+ index_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (index_arg);
+
+ // Define the first (and only) variant of this arg.
+ value_arg.arg_type = eArgTypeValue;
+ value_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg3.push_back (value_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ m_arguments.push_back (arg3);
+ }
+
+ virtual
+ ~CommandObjectSettingsInsertBefore () {}
+
+ // Overrides base class's behavior where WantsCompletion = !WantsRawCommandString.
+ virtual bool
+ WantsCompletion() { return true; }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ // Attempting to complete variable name
+ if (cursor_index < 2)
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+
+ Args cmd_args(command);
+ const size_t argc = cmd_args.GetArgumentCount ();
+
+ if (argc < 3)
+ {
+ result.AppendError ("'settings insert-before' takes more arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *var_name = cmd_args.GetArgumentAtIndex (0);
+ if ((var_name == NULL) || (var_name[0] == '\0'))
+ {
+ result.AppendError ("'settings insert-before' command requires a valid variable name; No value supplied");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Split the raw command into var_name, index_value, and value triple.
+ llvm::StringRef raw_str(command);
+ std::string var_value_string = raw_str.split(var_name).second.str();
+ const char *var_value_cstr = Args::StripSpaces(var_value_string, true, true, false);
+
+ Error error(m_interpreter.GetDebugger().SetPropertyValue (&m_exe_ctx,
+ eVarSetOperationInsertBefore,
+ var_name,
+ var_value_cstr));
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingInsertAfter
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsInsertAfter : public CommandObjectRaw
+{
+public:
+ CommandObjectSettingsInsertAfter (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "settings insert-after",
+ "Insert value(s) into an internal debugger settings array variable, immediately after the specified element.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentEntry arg3;
+ CommandArgumentData var_name_arg;
+ CommandArgumentData index_arg;
+ CommandArgumentData value_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (var_name_arg);
+
+ // Define the first (variant of this arg.
+ index_arg.arg_type = eArgTypeSettingIndex;
+ index_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (index_arg);
+
+ // Define the first (and only) variant of this arg.
+ value_arg.arg_type = eArgTypeValue;
+ value_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg3.push_back (value_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ m_arguments.push_back (arg3);
+ }
+
+ virtual
+ ~CommandObjectSettingsInsertAfter () {}
+
+ // Overrides base class's behavior where WantsCompletion = !WantsRawCommandString.
+ virtual bool
+ WantsCompletion() { return true; }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ // Attempting to complete variable name
+ if (cursor_index < 2)
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+
+ Args cmd_args(command);
+ const size_t argc = cmd_args.GetArgumentCount ();
+
+ if (argc < 3)
+ {
+ result.AppendError ("'settings insert-after' takes more arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *var_name = cmd_args.GetArgumentAtIndex (0);
+ if ((var_name == NULL) || (var_name[0] == '\0'))
+ {
+ result.AppendError ("'settings insert-after' command requires a valid variable name; No value supplied");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Split the raw command into var_name, index_value, and value triple.
+ llvm::StringRef raw_str(command);
+ std::string var_value_string = raw_str.split(var_name).second.str();
+ const char *var_value_cstr = Args::StripSpaces(var_value_string, true, true, false);
+
+ Error error(m_interpreter.GetDebugger().SetPropertyValue (&m_exe_ctx,
+ eVarSetOperationInsertAfter,
+ var_name,
+ var_value_cstr));
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsAppend
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsAppend : public CommandObjectRaw
+{
+public:
+ CommandObjectSettingsAppend (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "settings append",
+ "Append a new value to the end of an internal debugger settings array, dictionary or string variable.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData var_name_arg;
+ CommandArgumentData value_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (var_name_arg);
+
+ // Define the first (and only) variant of this arg.
+ value_arg.arg_type = eArgTypeValue;
+ value_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (value_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ }
+
+ virtual
+ ~CommandObjectSettingsAppend () {}
+
+ // Overrides base class's behavior where WantsCompletion = !WantsRawCommandString.
+ virtual bool
+ WantsCompletion() { return true; }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ // Attempting to complete variable name
+ if (cursor_index < 2)
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ Args cmd_args(command);
+ const size_t argc = cmd_args.GetArgumentCount ();
+
+ if (argc < 2)
+ {
+ result.AppendError ("'settings append' takes more arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *var_name = cmd_args.GetArgumentAtIndex (0);
+ if ((var_name == NULL) || (var_name[0] == '\0'))
+ {
+ result.AppendError ("'settings append' command requires a valid variable name; No value supplied");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Do not perform cmd_args.Shift() since StringRef is manipulating the
+ // raw character string later on.
+
+ // Split the raw command into var_name and value pair.
+ llvm::StringRef raw_str(command);
+ std::string var_value_string = raw_str.split(var_name).second.str();
+ const char *var_value_cstr = Args::StripSpaces(var_value_string, true, true, false);
+
+ Error error(m_interpreter.GetDebugger().SetPropertyValue (&m_exe_ctx,
+ eVarSetOperationAppend,
+ var_name,
+ var_value_cstr));
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsClear
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsClear : public CommandObjectParsed
+{
+public:
+ CommandObjectSettingsClear (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "settings clear",
+ "Erase all the contents of an internal debugger settings variables; this is only valid for variables with clearable types, i.e. strings, arrays or dictionaries.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData var_name_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (var_name_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectSettingsClear () {}
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ // Attempting to complete variable name
+ if (cursor_index < 2)
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ const size_t argc = command.GetArgumentCount ();
+
+ if (argc != 1)
+ {
+ result.AppendError ("'setttings clear' takes exactly one argument");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *var_name = command.GetArgumentAtIndex (0);
+ if ((var_name == NULL) || (var_name[0] == '\0'))
+ {
+ result.AppendError ("'settings clear' command requires a valid variable name; No value supplied");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Error error (m_interpreter.GetDebugger().SetPropertyValue (&m_exe_ctx,
+ eVarSetOperationClear,
+ var_name,
+ NULL));
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordSettings
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordSettings::CommandObjectMultiwordSettings (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "settings",
+ "A set of commands for manipulating internal settable debugger variables.",
+ "settings <command> [<command-options>]")
+{
+ LoadSubCommand ("set", CommandObjectSP (new CommandObjectSettingsSet (interpreter)));
+ LoadSubCommand ("show", CommandObjectSP (new CommandObjectSettingsShow (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectSettingsList (interpreter)));
+ LoadSubCommand ("remove", CommandObjectSP (new CommandObjectSettingsRemove (interpreter)));
+ LoadSubCommand ("replace", CommandObjectSP (new CommandObjectSettingsReplace (interpreter)));
+ LoadSubCommand ("insert-before", CommandObjectSP (new CommandObjectSettingsInsertBefore (interpreter)));
+ LoadSubCommand ("insert-after", CommandObjectSP (new CommandObjectSettingsInsertAfter (interpreter)));
+ LoadSubCommand ("append", CommandObjectSP (new CommandObjectSettingsAppend (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectSettingsClear (interpreter)));
+}
+
+CommandObjectMultiwordSettings::~CommandObjectMultiwordSettings ()
+{
+}
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectSettings.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSettings.h
new file mode 100644
index 0000000..eca7ade
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSettings.h
@@ -0,0 +1,41 @@
+//===-- CommandObjectSettings.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_CommandObjectSettings_h_
+#define liblldb_CommandObjectSettings_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/Options.h"
+
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordSettings
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordSettings : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordSettings (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordSettings ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectSettings_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.cpp
new file mode 100644
index 0000000..a08e393
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.cpp
@@ -0,0 +1,925 @@
+//===-- CommandObjectSource.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 "CommandObjectSource.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/FileLineResolver.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/SourceManager.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/TargetList.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Interpreter/Options.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectSourceInfo
+//-------------------------------------------------------------------------
+
+class CommandObjectSourceInfo : public CommandObjectParsed
+{
+
+ class CommandOptions : public Options
+ {
+ public:
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (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 'l':
+ start_line = Args::StringToUInt32 (option_arg, 0);
+ if (start_line == 0)
+ error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg);
+ break;
+
+ case 'f':
+ file_name = option_arg;
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ file_spec.Clear();
+ file_name.clear();
+ start_line = 0;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ FileSpec file_spec;
+ std::string file_name;
+ uint32_t start_line;
+
+ };
+
+public:
+ CommandObjectSourceInfo(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "source info",
+ "Display information about the source lines from the current executable's debug info.",
+ "source info [<cmd-options>]"),
+ m_options (interpreter)
+ {
+ }
+
+ ~CommandObjectSourceInfo ()
+ {
+ }
+
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ result.AppendError ("Not yet implemented");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectSourceInfo::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum, "The line number at which to start the display source."},
+{ LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#pragma mark CommandObjectSourceList
+//-------------------------------------------------------------------------
+// CommandObjectSourceList
+//-------------------------------------------------------------------------
+
+class CommandObjectSourceList : public CommandObjectParsed
+{
+
+ class CommandOptions : public Options
+ {
+ public:
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (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 'l':
+ start_line = Args::StringToUInt32 (option_arg, 0);
+ if (start_line == 0)
+ error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg);
+ break;
+
+ case 'c':
+ num_lines = Args::StringToUInt32 (option_arg, 0);
+ if (num_lines == 0)
+ error.SetErrorStringWithFormat("invalid line count: '%s'", option_arg);
+ break;
+
+ case 'f':
+ file_name = option_arg;
+ break;
+
+ case 'n':
+ symbol_name = option_arg;
+ break;
+
+ case 'a':
+ {
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ address = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ }
+ break;
+ case 's':
+ modules.push_back (std::string (option_arg));
+ break;
+
+ case 'b':
+ show_bp_locs = true;
+ break;
+ case 'r':
+ reverse = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ file_spec.Clear();
+ file_name.clear();
+ symbol_name.clear();
+ address = LLDB_INVALID_ADDRESS;
+ start_line = 0;
+ num_lines = 0;
+ show_bp_locs = false;
+ reverse = false;
+ modules.clear();
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ FileSpec file_spec;
+ std::string file_name;
+ std::string symbol_name;
+ lldb::addr_t address;
+ uint32_t start_line;
+ uint32_t num_lines;
+ STLStringArray modules;
+ bool show_bp_locs;
+ bool reverse;
+ };
+
+public:
+ CommandObjectSourceList(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "source list",
+ "Display source code (as specified) based on the current executable's debug info.",
+ NULL,
+ eFlagRequiresTarget),
+ m_options (interpreter)
+ {
+ }
+
+ ~CommandObjectSourceList ()
+ {
+ }
+
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ virtual const char *
+ GetRepeatCommand (Args &current_command_args, uint32_t index)
+ {
+ // This is kind of gross, but the command hasn't been parsed yet so we can't look at the option
+ // values for this invocation... I have to scan the arguments directly.
+ size_t num_args = current_command_args.GetArgumentCount();
+ bool is_reverse = false;
+ for (size_t i = 0 ; i < num_args; i++)
+ {
+ const char *arg = current_command_args.GetArgumentAtIndex(i);
+ if (arg && (strcmp(arg, "-r") == 0 || strcmp(arg, "--reverse") == 0))
+ {
+ is_reverse = true;
+ }
+ }
+ if (is_reverse)
+ {
+ if (m_reverse_name.empty())
+ {
+ m_reverse_name = m_cmd_name;
+ m_reverse_name.append (" -r");
+ }
+ return m_reverse_name.c_str();
+ }
+ else
+ return m_cmd_name.c_str();
+ }
+
+protected:
+
+ struct SourceInfo
+ {
+ ConstString function;
+ LineEntry line_entry;
+
+ SourceInfo (const ConstString &name, const LineEntry &line_entry) :
+ function(name),
+ line_entry(line_entry)
+ {
+ }
+
+ SourceInfo () :
+ function(),
+ line_entry()
+ {
+ }
+
+ bool
+ IsValid () const
+ {
+ return (bool)function && line_entry.IsValid();
+ }
+
+ bool
+ operator == (const SourceInfo &rhs) const
+ {
+ return function == rhs.function &&
+ line_entry.file == rhs.line_entry.file &&
+ line_entry.line == rhs.line_entry.line;
+ }
+
+ bool
+ operator != (const SourceInfo &rhs) const
+ {
+ return function != rhs.function ||
+ line_entry.file != rhs.line_entry.file ||
+ line_entry.line != rhs.line_entry.line;
+ }
+
+ bool
+ operator < (const SourceInfo &rhs) const
+ {
+ if (function.GetCString() < rhs.function.GetCString())
+ return true;
+ if (line_entry.file.GetDirectory().GetCString() < rhs.line_entry.file.GetDirectory().GetCString())
+ return true;
+ if (line_entry.file.GetFilename().GetCString() < rhs.line_entry.file.GetFilename().GetCString())
+ return true;
+ if (line_entry.line < rhs.line_entry.line)
+ return true;
+ return false;
+ }
+ };
+
+ size_t
+ DisplayFunctionSource (const SymbolContext &sc,
+ SourceInfo &source_info,
+ CommandReturnObject &result)
+ {
+ if (!source_info.IsValid())
+ {
+ source_info.function = sc.GetFunctionName();
+ source_info.line_entry = sc.GetFunctionStartLineEntry();
+ }
+
+ if (sc.function)
+ {
+ Target *target = m_exe_ctx.GetTargetPtr();
+
+ FileSpec start_file;
+ uint32_t start_line;
+ uint32_t end_line;
+ FileSpec end_file;
+
+ if (sc.block == NULL)
+ {
+ // Not an inlined function
+ sc.function->GetStartLineSourceInfo (start_file, start_line);
+ if (start_line == 0)
+ {
+ result.AppendErrorWithFormat("Could not find line information for start of function: \"%s\".\n", source_info.function.GetCString());
+ result.SetStatus (eReturnStatusFailed);
+ return 0;
+ }
+ sc.function->GetEndLineSourceInfo (end_file, end_line);
+ }
+ else
+ {
+ // We have an inlined function
+ start_file = source_info.line_entry.file;
+ start_line = source_info.line_entry.line;
+ end_line = start_line + m_options.num_lines;
+ }
+
+ // This is a little hacky, but the first line table entry for a function points to the "{" that
+ // starts the function block. It would be nice to actually get the function
+ // declaration in there too. So back up a bit, but not further than what you're going to display.
+ uint32_t extra_lines;
+ if (m_options.num_lines >= 10)
+ extra_lines = 5;
+ else
+ extra_lines = m_options.num_lines/2;
+ uint32_t line_no;
+ if (start_line <= extra_lines)
+ line_no = 1;
+ else
+ line_no = start_line - extra_lines;
+
+ // For fun, if the function is shorter than the number of lines we're supposed to display,
+ // only display the function...
+ if (end_line != 0)
+ {
+ if (m_options.num_lines > end_line - line_no)
+ m_options.num_lines = end_line - line_no + extra_lines;
+ }
+
+ m_breakpoint_locations.Clear();
+
+ if (m_options.show_bp_locs)
+ {
+ const bool show_inlines = true;
+ m_breakpoint_locations.Reset (start_file, 0, show_inlines);
+ SearchFilter target_search_filter (m_exe_ctx.GetTargetSP());
+ target_search_filter.Search (m_breakpoint_locations);
+ }
+
+ result.AppendMessageWithFormat("File: %s\n", start_file.GetPath().c_str());
+ return target->GetSourceManager().DisplaySourceLinesWithLineNumbers (start_file,
+ line_no,
+ 0,
+ m_options.num_lines,
+ "",
+ &result.GetOutputStream(),
+ GetBreakpointLocations ());
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Could not find function info for: \"%s\".\n", m_options.symbol_name.c_str());
+ }
+ return 0;
+ }
+
+ // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols functions
+ // "take a possibly empty vector of strings which are names of modules, and
+ // run the two search functions on the subset of the full module list that
+ // matches the strings in the input vector". If we wanted to put these somewhere,
+ // there should probably be a module-filter-list that can be passed to the
+ // various ModuleList::Find* calls, which would either be a vector of string
+ // names or a ModuleSpecList.
+ size_t FindMatchingFunctions (Target *target, const ConstString &name, SymbolContextList& sc_list)
+ {
+ // Displaying the source for a symbol:
+ bool include_inlines = true;
+ bool append = true;
+ bool include_symbols = false;
+ size_t num_matches = 0;
+
+ if (m_options.num_lines == 0)
+ m_options.num_lines = 10;
+
+ const size_t num_modules = m_options.modules.size();
+ if (num_modules > 0)
+ {
+ ModuleList matching_modules;
+ for (size_t i = 0; i < num_modules; ++i)
+ {
+ FileSpec module_file_spec(m_options.modules[i].c_str(), false);
+ if (module_file_spec)
+ {
+ ModuleSpec module_spec (module_file_spec);
+ matching_modules.Clear();
+ target->GetImages().FindModules (module_spec, matching_modules);
+ num_matches += matching_modules.FindFunctions (name, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list);
+ }
+ }
+ }
+ else
+ {
+ num_matches = target->GetImages().FindFunctions (name, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list);
+ }
+ return num_matches;
+ }
+
+ size_t FindMatchingFunctionSymbols (Target *target, const ConstString &name, SymbolContextList& sc_list)
+ {
+ size_t num_matches = 0;
+ const size_t num_modules = m_options.modules.size();
+ if (num_modules > 0)
+ {
+ ModuleList matching_modules;
+ for (size_t i = 0; i < num_modules; ++i)
+ {
+ FileSpec module_file_spec(m_options.modules[i].c_str(), false);
+ if (module_file_spec)
+ {
+ ModuleSpec module_spec (module_file_spec);
+ matching_modules.Clear();
+ target->GetImages().FindModules (module_spec, matching_modules);
+ num_matches += matching_modules.FindFunctionSymbols (name, eFunctionNameTypeAuto, sc_list);
+ }
+ }
+ }
+ else
+ {
+ num_matches = target->GetImages().FindFunctionSymbols (name, eFunctionNameTypeAuto, sc_list);
+ }
+ return num_matches;
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc != 0)
+ {
+ result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", GetCommandName());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Target *target = m_exe_ctx.GetTargetPtr();
+
+ if (!m_options.symbol_name.empty())
+ {
+ SymbolContextList sc_list;
+ ConstString name(m_options.symbol_name.c_str());
+
+ // Displaying the source for a symbol. Search for function named name.
+ size_t num_matches = FindMatchingFunctions (target, name, sc_list);
+ if (!num_matches)
+ {
+ // If we didn't find any functions with that name, try searching for symbols
+ // that line up exactly with function addresses.
+ SymbolContextList sc_list_symbols;
+ size_t num_symbol_matches = FindMatchingFunctionSymbols (target, name, sc_list_symbols);
+ for (size_t i = 0; i < num_symbol_matches; i++)
+ {
+ SymbolContext sc;
+ sc_list_symbols.GetContextAtIndex (i, sc);
+ if (sc.symbol)
+ {
+ const Address &base_address = sc.symbol->GetAddress();
+ Function *function = base_address.CalculateSymbolContextFunction();
+ if (function)
+ {
+ sc_list.Append (SymbolContext(function));
+ num_matches++;
+ break;
+ }
+ }
+ }
+ }
+
+ if (num_matches == 0)
+ {
+ result.AppendErrorWithFormat("Could not find function named: \"%s\".\n", m_options.symbol_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (num_matches > 1)
+ {
+ std::set<SourceInfo> source_match_set;
+
+ bool displayed_something = false;
+ for (size_t i = 0; i < num_matches; i++)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex (i, sc);
+ SourceInfo source_info (sc.GetFunctionName(),
+ sc.GetFunctionStartLineEntry());
+
+ if (source_info.IsValid())
+ {
+ if (source_match_set.find(source_info) == source_match_set.end())
+ {
+ source_match_set.insert(source_info);
+ if (DisplayFunctionSource (sc, source_info, result))
+ displayed_something = true;
+ }
+ }
+ }
+
+ if (displayed_something)
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ else
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex (0, sc);
+ SourceInfo source_info;
+
+ if (DisplayFunctionSource (sc, source_info, result))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ return result.Succeeded();
+ }
+ else if (m_options.address != LLDB_INVALID_ADDRESS)
+ {
+ Address so_addr;
+ StreamString error_strm;
+ SymbolContextList sc_list;
+
+ if (target->GetSectionLoadList().IsEmpty())
+ {
+ // The target isn't loaded yet, we need to lookup the file address
+ // in all modules
+ const ModuleList &module_list = target->GetImages();
+ const size_t num_modules = module_list.GetSize();
+ for (size_t i=0; i<num_modules; ++i)
+ {
+ ModuleSP module_sp (module_list.GetModuleAtIndex(i));
+ if (module_sp && module_sp->ResolveFileAddress(m_options.address, so_addr))
+ {
+ SymbolContext sc;
+ sc.Clear(true);
+ if (module_sp->ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, sc) & eSymbolContextLineEntry)
+ sc_list.Append(sc);
+ }
+ }
+
+ if (sc_list.GetSize() == 0)
+ {
+ result.AppendErrorWithFormat("no modules have source information for file address 0x%" PRIx64 ".\n",
+ m_options.address);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ // The target has some things loaded, resolve this address to a
+ // compile unit + file + line and display
+ if (target->GetSectionLoadList().ResolveLoadAddress (m_options.address, so_addr))
+ {
+ ModuleSP module_sp (so_addr.GetModule());
+ if (module_sp)
+ {
+ SymbolContext sc;
+ sc.Clear(true);
+ if (module_sp->ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, sc) & eSymbolContextLineEntry)
+ {
+ sc_list.Append(sc);
+ }
+ else
+ {
+ so_addr.Dump(&error_strm, NULL, Address::DumpStyleModuleWithFileAddress);
+ result.AppendErrorWithFormat("address resolves to %s, but there is no line table information available for this address.\n",
+ error_strm.GetData());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+
+ if (sc_list.GetSize() == 0)
+ {
+ result.AppendErrorWithFormat("no modules contain load address 0x%" PRIx64 ".\n", m_options.address);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ uint32_t num_matches = sc_list.GetSize();
+ for (uint32_t i=0; i<num_matches; ++i)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(i, sc);
+ if (sc.comp_unit)
+ {
+ if (m_options.show_bp_locs)
+ {
+ m_breakpoint_locations.Clear();
+ const bool show_inlines = true;
+ m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines);
+ SearchFilter target_search_filter (target->shared_from_this());
+ target_search_filter.Search (m_breakpoint_locations);
+ }
+
+ bool show_fullpaths = true;
+ bool show_module = true;
+ bool show_inlined_frames = true;
+ sc.DumpStopContext(&result.GetOutputStream(),
+ m_exe_ctx.GetBestExecutionContextScope(),
+ sc.line_entry.range.GetBaseAddress(),
+ show_fullpaths,
+ show_module,
+ show_inlined_frames);
+ result.GetOutputStream().EOL();
+
+ if (m_options.num_lines == 0)
+ m_options.num_lines = 10;
+
+ size_t lines_to_back_up = m_options.num_lines >= 10 ? 5 : m_options.num_lines/2;
+
+ target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit,
+ sc.line_entry.line,
+ lines_to_back_up,
+ m_options.num_lines - lines_to_back_up,
+ "->",
+ &result.GetOutputStream(),
+ GetBreakpointLocations ());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ }
+ }
+ else if (m_options.file_name.empty())
+ {
+ // Last valid source manager context, or the current frame if no
+ // valid last context in source manager.
+ // One little trick here, if you type the exact same list command twice in a row, it is
+ // more likely because you typed it once, then typed it again
+ if (m_options.start_line == 0)
+ {
+ if (target->GetSourceManager().DisplayMoreWithLineNumbers (&result.GetOutputStream(),
+ m_options.num_lines,
+ m_options.reverse,
+ GetBreakpointLocations ()))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ }
+ else
+ {
+ if (m_options.num_lines == 0)
+ m_options.num_lines = 10;
+
+ if (m_options.show_bp_locs)
+ {
+ SourceManager::FileSP last_file_sp (target->GetSourceManager().GetLastFile ());
+ if (last_file_sp)
+ {
+ const bool show_inlines = true;
+ m_breakpoint_locations.Reset (last_file_sp->GetFileSpec(), 0, show_inlines);
+ SearchFilter target_search_filter (target->shared_from_this());
+ target_search_filter.Search (m_breakpoint_locations);
+ }
+ }
+ else
+ m_breakpoint_locations.Clear();
+
+ if (target->GetSourceManager().DisplaySourceLinesWithLineNumbersUsingLastFile(
+ m_options.start_line, // Line to display
+ m_options.num_lines, // Lines after line to
+ UINT32_MAX, // Don't mark "line"
+ "", // Don't mark "line"
+ &result.GetOutputStream(),
+ GetBreakpointLocations ()))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+
+ }
+ }
+ else
+ {
+ const char *filename = m_options.file_name.c_str();
+
+ bool check_inlines = false;
+ SymbolContextList sc_list;
+ size_t num_matches = 0;
+
+ if (m_options.modules.size() > 0)
+ {
+ ModuleList matching_modules;
+ for (size_t i = 0, e = m_options.modules.size(); i < e; ++i)
+ {
+ FileSpec module_file_spec(m_options.modules[i].c_str(), false);
+ if (module_file_spec)
+ {
+ ModuleSpec module_spec (module_file_spec);
+ matching_modules.Clear();
+ target->GetImages().FindModules (module_spec, matching_modules);
+ num_matches += matching_modules.ResolveSymbolContextForFilePath (filename,
+ 0,
+ check_inlines,
+ eSymbolContextModule | eSymbolContextCompUnit,
+ sc_list);
+ }
+ }
+ }
+ else
+ {
+ num_matches = target->GetImages().ResolveSymbolContextForFilePath (filename,
+ 0,
+ check_inlines,
+ eSymbolContextModule | eSymbolContextCompUnit,
+ sc_list);
+ }
+
+ if (num_matches == 0)
+ {
+ result.AppendErrorWithFormat("Could not find source file \"%s\".\n",
+ m_options.file_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (num_matches > 1)
+ {
+ bool got_multiple = false;
+ FileSpec *test_cu_spec = NULL;
+
+ for (unsigned i = 0; i < num_matches; i++)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(i, sc);
+ if (sc.comp_unit)
+ {
+ if (test_cu_spec)
+ {
+ if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
+ got_multiple = true;
+ break;
+ }
+ else
+ test_cu_spec = sc.comp_unit;
+ }
+ }
+ if (got_multiple)
+ {
+ result.AppendErrorWithFormat("Multiple source files found matching: \"%s.\"\n",
+ m_options.file_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc))
+ {
+ if (sc.comp_unit)
+ {
+ if (m_options.show_bp_locs)
+ {
+ const bool show_inlines = true;
+ m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines);
+ SearchFilter target_search_filter (target->shared_from_this());
+ target_search_filter.Search (m_breakpoint_locations);
+ }
+ else
+ m_breakpoint_locations.Clear();
+
+ if (m_options.num_lines == 0)
+ m_options.num_lines = 10;
+
+ target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit,
+ m_options.start_line,
+ 0,
+ m_options.num_lines,
+ "",
+ &result.GetOutputStream(),
+ GetBreakpointLocations ());
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n",
+ m_options.file_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ return result.Succeeded();
+ }
+
+ const SymbolContextList *
+ GetBreakpointLocations ()
+ {
+ if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0)
+ return &m_breakpoint_locations.GetFileLineMatches();
+ return NULL;
+ }
+ CommandOptions m_options;
+ FileLineResolver m_breakpoint_locations;
+ std::string m_reverse_name;
+
+};
+
+OptionDefinition
+CommandObjectSourceList::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "count", 'c', required_argument, NULL, 0, eArgTypeCount, "The number of source lines to display."},
+{ LLDB_OPT_SET_1 |
+ LLDB_OPT_SET_2 , false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Look up the source file in the given shared library."},
+{ LLDB_OPT_SET_ALL, false, "show-breakpoints", 'b', no_argument, NULL, 0, eArgTypeNone, "Show the line table locations from the debug information that indicate valid places to set source level breakpoints."},
+{ LLDB_OPT_SET_1 , false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."},
+{ LLDB_OPT_SET_1 , false, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum, "The line number at which to start the display source."},
+{ LLDB_OPT_SET_2 , false, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeSymbol, "The name of a function whose source to display."},
+{ LLDB_OPT_SET_3 , false, "address",'a', required_argument, NULL, 0, eArgTypeAddressOrExpression, "Lookup the address and display the source information for the corresponding file and line."},
+{ LLDB_OPT_SET_4, false, "reverse", 'r', no_argument, NULL, 0, eArgTypeNone, "Reverse the listing to look backwards from the last displayed block of source."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#pragma mark CommandObjectMultiwordSource
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordSource
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordSource::CommandObjectMultiwordSource (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "source",
+ "A set of commands for accessing source file information",
+ "source <subcommand> [<subcommand-options>]")
+{
+ // "source info" isn't implemented yet...
+ //LoadSubCommand ("info", CommandObjectSP (new CommandObjectSourceInfo (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectSourceList (interpreter)));
+}
+
+CommandObjectMultiwordSource::~CommandObjectMultiwordSource ()
+{
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.h
new file mode 100644
index 0000000..0daef13
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.h
@@ -0,0 +1,40 @@
+//===-- CommandObjectSource.h.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_CommandObjectSource_h_
+#define liblldb_CommandObjectSource_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Core/STLUtils.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordSource
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordSource : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordSource (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordSource ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectSource.h_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectSyntax.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSyntax.cpp
new file mode 100644
index 0000000..d2021ea
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSyntax.cpp
@@ -0,0 +1,113 @@
+//===-- CommandObjectSyntax.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 "CommandObjectSyntax.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/Options.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectSyntax
+//-------------------------------------------------------------------------
+
+CommandObjectSyntax::CommandObjectSyntax (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "syntax",
+ "Shows the correct syntax for a given debugger command.",
+ "syntax <command>")
+{
+ CommandArgumentEntry arg;
+ CommandArgumentData command_arg;
+
+ // Define the first (and only) variant of this arg.
+ command_arg.arg_type = eArgTypeCommandName;
+ command_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (command_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+}
+
+CommandObjectSyntax::~CommandObjectSyntax()
+{
+}
+
+
+bool
+CommandObjectSyntax::DoExecute (Args& command, CommandReturnObject &result)
+{
+ CommandObject::CommandMap::iterator pos;
+ CommandObject *cmd_obj;
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc > 0)
+ {
+ cmd_obj = m_interpreter.GetCommandObject (command.GetArgumentAtIndex(0));
+ bool all_okay = true;
+ for (size_t i = 1; i < argc; ++i)
+ {
+ std::string sub_command = command.GetArgumentAtIndex (i);
+ if (!cmd_obj->IsMultiwordObject())
+ all_okay = false;
+ else
+ {
+ cmd_obj = cmd_obj->GetSubcommandObject(sub_command.c_str());
+ if (!cmd_obj)
+ all_okay = false;
+ }
+ }
+
+ if (all_okay && (cmd_obj != NULL))
+ {
+ Stream &output_strm = result.GetOutputStream();
+ if (cmd_obj->GetOptions() != NULL)
+ {
+ output_strm.Printf ("\nSyntax: %s\n", cmd_obj->GetSyntax());
+ output_strm.Printf ("(Try 'help %s' for more information on command options syntax.)\n",
+ cmd_obj->GetCommandName());
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ output_strm.Printf ("\nSyntax: %s\n", cmd_obj->GetSyntax());
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+ else
+ {
+ std::string cmd_string;
+ command.GetCommandString (cmd_string);
+ result.AppendErrorWithFormat ("'%s' is not a known command.\n", cmd_string.c_str());
+ result.AppendError ("Try 'help' to see a current list of commands.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("Must call 'syntax' with a valid command.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+}
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectSyntax.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSyntax.h
new file mode 100644
index 0000000..47bf85f
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSyntax.h
@@ -0,0 +1,44 @@
+//===-- CommandObjectSyntax.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_CommandObjectSyntax_h_
+#define liblldb_CommandObjectSyntax_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectSyntax
+//-------------------------------------------------------------------------
+
+class CommandObjectSyntax : public CommandObjectParsed
+{
+public:
+
+ CommandObjectSyntax (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectSyntax ();
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result);
+
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectSyntax_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.cpp
new file mode 100644
index 0000000..dd0e2a0
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.cpp
@@ -0,0 +1,5354 @@
+//===-- CommandObjectTarget.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 "CommandObjectTarget.h"
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionGroupArchitecture.h"
+#include "lldb/Interpreter/OptionGroupBoolean.h"
+#include "lldb/Interpreter/OptionGroupFile.h"
+#include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Interpreter/OptionGroupVariable.h"
+#include "lldb/Interpreter/OptionGroupPlatform.h"
+#include "lldb/Interpreter/OptionGroupUInt64.h"
+#include "lldb/Interpreter/OptionGroupUUID.h"
+#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+static void
+DumpTargetInfo (uint32_t target_idx, Target *target, const char *prefix_cstr, bool show_stopped_process_status, Stream &strm)
+{
+ const ArchSpec &target_arch = target->GetArchitecture();
+
+ Module *exe_module = target->GetExecutableModulePointer();
+ char exe_path[PATH_MAX];
+ bool exe_valid = false;
+ if (exe_module)
+ exe_valid = exe_module->GetFileSpec().GetPath (exe_path, sizeof(exe_path));
+
+ if (!exe_valid)
+ ::strcpy (exe_path, "<none>");
+
+ strm.Printf ("%starget #%u: %s", prefix_cstr ? prefix_cstr : "", target_idx, exe_path);
+
+ uint32_t properties = 0;
+ if (target_arch.IsValid())
+ {
+ strm.Printf ("%sarch=%s", properties++ > 0 ? ", " : " ( ", target_arch.GetTriple().str().c_str());
+ properties++;
+ }
+ PlatformSP platform_sp (target->GetPlatform());
+ if (platform_sp)
+ strm.Printf ("%splatform=%s", properties++ > 0 ? ", " : " ( ", platform_sp->GetName().GetCString());
+
+ ProcessSP process_sp (target->GetProcessSP());
+ bool show_process_status = false;
+ if (process_sp)
+ {
+ lldb::pid_t pid = process_sp->GetID();
+ StateType state = process_sp->GetState();
+ if (show_stopped_process_status)
+ show_process_status = StateIsStoppedState(state, true);
+ const char *state_cstr = StateAsCString (state);
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ strm.Printf ("%spid=%" PRIu64, properties++ > 0 ? ", " : " ( ", pid);
+ strm.Printf ("%sstate=%s", properties++ > 0 ? ", " : " ( ", state_cstr);
+ }
+ if (properties > 0)
+ strm.PutCString (" )\n");
+ else
+ strm.EOL();
+ if (show_process_status)
+ {
+ const bool only_threads_with_stop_reason = true;
+ const uint32_t start_frame = 0;
+ const uint32_t num_frames = 1;
+ const uint32_t num_frames_with_source = 1;
+ process_sp->GetStatus (strm);
+ process_sp->GetThreadStatus (strm,
+ only_threads_with_stop_reason,
+ start_frame,
+ num_frames,
+ num_frames_with_source);
+
+ }
+}
+
+static uint32_t
+DumpTargetList (TargetList &target_list, bool show_stopped_process_status, Stream &strm)
+{
+ const uint32_t num_targets = target_list.GetNumTargets();
+ if (num_targets)
+ {
+ TargetSP selected_target_sp (target_list.GetSelectedTarget());
+ strm.PutCString ("Current targets:\n");
+ for (uint32_t i=0; i<num_targets; ++i)
+ {
+ TargetSP target_sp (target_list.GetTargetAtIndex (i));
+ if (target_sp)
+ {
+ bool is_selected = target_sp.get() == selected_target_sp.get();
+ DumpTargetInfo (i,
+ target_sp.get(),
+ is_selected ? "* " : " ",
+ show_stopped_process_status,
+ strm);
+ }
+ }
+ }
+ return num_targets;
+}
+#pragma mark CommandObjectTargetCreate
+
+//-------------------------------------------------------------------------
+// "target create"
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetCreate : public CommandObjectParsed
+{
+public:
+ CommandObjectTargetCreate(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target create",
+ "Create a target using the argument as the main executable.",
+ NULL),
+ m_option_group (interpreter),
+ m_arch_option (),
+ m_platform_options(true), // Do include the "--platform" option in the platform settings by passing true
+ m_core_file (LLDB_OPT_SET_1, false, "core", 'c', 0, eArgTypeFilename, "Fullpath to a core file to use for this target."),
+ m_symbol_file (LLDB_OPT_SET_1, false, "symfile", 's', 0, eArgTypeFilename, "Fullpath to a stand alone debug symbols file for when debug symbols are not in the executable."),
+ m_remote_file (LLDB_OPT_SET_1, false, "remote-file", 'r', 0, eArgTypeFilename, "Fullpath to the file on the remote host if debugging remotely."),
+ m_add_dependents (LLDB_OPT_SET_1, false, "no-dependents", 'd', "Don't load dependent files when creating the target, just add the specified executable.", true, true)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData file_arg;
+
+ // Define the first (and only) variant of this arg.
+ file_arg.arg_type = eArgTypeFilename;
+ file_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (file_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+ m_option_group.Append (&m_arch_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_platform_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_core_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_symbol_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_remote_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_add_dependents, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ ~CommandObjectTargetCreate ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eDiskFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ FileSpec core_file (m_core_file.GetOptionValue().GetCurrentValue());
+ FileSpec remote_file (m_remote_file.GetOptionValue().GetCurrentValue());
+
+ if (argc == 1 || core_file)
+ {
+ FileSpec symfile (m_symbol_file.GetOptionValue().GetCurrentValue());
+ if (symfile)
+ {
+ if (!symfile.Exists())
+ {
+ char symfile_path[PATH_MAX];
+ symfile.GetPath(symfile_path, sizeof(symfile_path));
+ result.AppendErrorWithFormat("invalid symbol file path '%s'", symfile_path);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ const char *file_path = command.GetArgumentAtIndex(0);
+ Timer scoped_timer(__PRETTY_FUNCTION__, "(lldb) target create '%s'", file_path);
+ TargetSP target_sp;
+ Debugger &debugger = m_interpreter.GetDebugger();
+ const char *arch_cstr = m_arch_option.GetArchitectureName();
+ const bool get_dependent_files = m_add_dependents.GetOptionValue().GetCurrentValue();
+ Error error (debugger.GetTargetList().CreateTarget (debugger,
+ file_path,
+ arch_cstr,
+ get_dependent_files,
+ &m_platform_options,
+ target_sp));
+
+ if (target_sp)
+ {
+ if (symfile || remote_file)
+ {
+ ModuleSP module_sp (target_sp->GetExecutableModule());
+ if (module_sp)
+ {
+ if (symfile)
+ module_sp->SetSymbolFileFileSpec(symfile);
+ if (remote_file)
+ {
+ std::string remote_path = remote_file.GetPath();
+ target_sp->SetArg0(remote_path.c_str());
+ module_sp->SetPlatformFileSpec(remote_file);
+ }
+ }
+ }
+
+ debugger.GetTargetList().SetSelectedTarget(target_sp.get());
+ if (core_file)
+ {
+ char core_path[PATH_MAX];
+ core_file.GetPath(core_path, sizeof(core_path));
+ if (core_file.Exists())
+ {
+ FileSpec core_file_dir;
+ core_file_dir.GetDirectory() = core_file.GetDirectory();
+ target_sp->GetExecutableSearchPaths ().Append (core_file_dir);
+
+ ProcessSP process_sp (target_sp->CreateProcess (m_interpreter.GetDebugger().GetListener(), NULL, &core_file));
+
+ if (process_sp)
+ {
+ // Seems wierd that we Launch a core file, but that is
+ // what we do!
+ error = process_sp->LoadCore();
+
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString("can't find plug-in for core file"));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ result.AppendMessageWithFormat ("Core file '%s' (%s) was loaded.\n", core_path, target_sp->GetArchitecture().GetArchitectureName());
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Unable to find process plug-in for core file '%s'\n", core_path);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Core file '%s' does not exist\n", core_path);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendMessageWithFormat ("Current executable set to '%s' (%s).\n", file_path, target_sp->GetArchitecture().GetArchitectureName());
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+ else
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("'%s' takes exactly one executable path argument, or use the --core-file option.\n", m_cmd_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+
+ }
+
+private:
+ OptionGroupOptions m_option_group;
+ OptionGroupArchitecture m_arch_option;
+ OptionGroupPlatform m_platform_options;
+ OptionGroupFile m_core_file;
+ OptionGroupFile m_symbol_file;
+ OptionGroupFile m_remote_file;
+ OptionGroupBoolean m_add_dependents;
+};
+
+#pragma mark CommandObjectTargetList
+
+//----------------------------------------------------------------------
+// "target list"
+//----------------------------------------------------------------------
+
+class CommandObjectTargetList : public CommandObjectParsed
+{
+public:
+ CommandObjectTargetList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target list",
+ "List all current targets in the current debug session.",
+ NULL,
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetList ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ if (args.GetArgumentCount() == 0)
+ {
+ Stream &strm = result.GetOutputStream();
+
+ bool show_stopped_process_status = false;
+ if (DumpTargetList (m_interpreter.GetDebugger().GetTargetList(), show_stopped_process_status, strm) == 0)
+ {
+ strm.PutCString ("No targets.\n");
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError ("the 'target list' command takes no arguments\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+
+#pragma mark CommandObjectTargetSelect
+
+//----------------------------------------------------------------------
+// "target select"
+//----------------------------------------------------------------------
+
+class CommandObjectTargetSelect : public CommandObjectParsed
+{
+public:
+ CommandObjectTargetSelect (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target select",
+ "Select a target as the current target by target index.",
+ NULL,
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetSelect ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ if (args.GetArgumentCount() == 1)
+ {
+ bool success = false;
+ const char *target_idx_arg = args.GetArgumentAtIndex(0);
+ uint32_t target_idx = Args::StringToUInt32 (target_idx_arg, UINT32_MAX, 0, &success);
+ if (success)
+ {
+ TargetList &target_list = m_interpreter.GetDebugger().GetTargetList();
+ const uint32_t num_targets = target_list.GetNumTargets();
+ if (target_idx < num_targets)
+ {
+ TargetSP target_sp (target_list.GetTargetAtIndex (target_idx));
+ if (target_sp)
+ {
+ Stream &strm = result.GetOutputStream();
+ target_list.SetSelectedTarget (target_sp.get());
+ bool show_stopped_process_status = false;
+ DumpTargetList (target_list, show_stopped_process_status, strm);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("target #%u is NULL in target list\n", target_idx);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("index %u is out of range, valid target indexes are 0 - %u\n",
+ target_idx,
+ num_targets - 1);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("invalid index string value '%s'\n", target_idx_arg);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("'target select' takes a single argument: a target index\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+#pragma mark CommandObjectTargetSelect
+
+//----------------------------------------------------------------------
+// "target delete"
+//----------------------------------------------------------------------
+
+class CommandObjectTargetDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectTargetDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target delete",
+ "Delete one or more targets by target index.",
+ NULL,
+ 0),
+ m_option_group (interpreter),
+ m_cleanup_option (LLDB_OPT_SET_1, false, "clean", 'c', "Perform extra cleanup to minimize memory consumption after deleting the target.", false, false)
+ {
+ m_option_group.Append (&m_cleanup_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectTargetDelete ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ const size_t argc = args.GetArgumentCount();
+ std::vector<TargetSP> delete_target_list;
+ TargetList &target_list = m_interpreter.GetDebugger().GetTargetList();
+ bool success = true;
+ TargetSP target_sp;
+ if (argc > 0)
+ {
+ const uint32_t num_targets = target_list.GetNumTargets();
+ // Bail out if don't have any targets.
+ if (num_targets == 0) {
+ result.AppendError("no targets to delete");
+ result.SetStatus(eReturnStatusFailed);
+ success = false;
+ }
+
+ for (uint32_t arg_idx = 0; success && arg_idx < argc; ++arg_idx)
+ {
+ const char *target_idx_arg = args.GetArgumentAtIndex(arg_idx);
+ uint32_t target_idx = Args::StringToUInt32 (target_idx_arg, UINT32_MAX, 0, &success);
+ if (success)
+ {
+ if (target_idx < num_targets)
+ {
+ target_sp = target_list.GetTargetAtIndex (target_idx);
+ if (target_sp)
+ {
+ delete_target_list.push_back (target_sp);
+ continue;
+ }
+ }
+ if (num_targets > 1)
+ result.AppendErrorWithFormat ("target index %u is out of range, valid target indexes are 0 - %u\n",
+ target_idx,
+ num_targets - 1);
+ else
+ result.AppendErrorWithFormat("target index %u is out of range, the only valid index is 0\n",
+ target_idx);
+
+ result.SetStatus (eReturnStatusFailed);
+ success = false;
+ }
+ else
+ {
+ result.AppendErrorWithFormat("invalid target index '%s'\n", target_idx_arg);
+ result.SetStatus (eReturnStatusFailed);
+ success = false;
+ }
+ }
+
+ }
+ else
+ {
+ target_sp = target_list.GetSelectedTarget();
+ if (target_sp)
+ {
+ delete_target_list.push_back (target_sp);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("no target is currently selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ success = false;
+ }
+ }
+ if (success)
+ {
+ const size_t num_targets_to_delete = delete_target_list.size();
+ for (size_t idx = 0; idx < num_targets_to_delete; ++idx)
+ {
+ target_sp = delete_target_list[idx];
+ target_list.DeleteTarget(target_sp);
+ target_sp->Destroy();
+ }
+ // If "--clean" was specified, prune any orphaned shared modules from
+ // the global shared module list
+ if (m_cleanup_option.GetOptionValue ())
+ {
+ const bool mandatory = true;
+ ModuleList::RemoveOrphanSharedModules(mandatory);
+ }
+ result.GetOutputStream().Printf("%u targets deleted.\n", (uint32_t)num_targets_to_delete);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+
+ return result.Succeeded();
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupBoolean m_cleanup_option;
+};
+
+
+#pragma mark CommandObjectTargetVariable
+
+//----------------------------------------------------------------------
+// "target variable"
+//----------------------------------------------------------------------
+
+class CommandObjectTargetVariable : public CommandObjectParsed
+{
+public:
+ CommandObjectTargetVariable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target variable",
+ "Read global variable(s) prior to, or while running your binary.",
+ NULL,
+ eFlagRequiresTarget),
+ m_option_group (interpreter),
+ m_option_variable (false), // Don't include frame options
+ m_option_format (eFormatDefault),
+ m_option_compile_units (LLDB_OPT_SET_1, false, "file", 'file', 0, eArgTypeFilename, "A basename or fullpath to a file that contains global variables. This option can be specified multiple times."),
+ m_option_shared_libraries (LLDB_OPT_SET_1, false, "shlib",'shlb', 0, eArgTypeFilename, "A basename or fullpath to a shared library to use in the search for global variables. This option can be specified multiple times."),
+ m_varobj_options()
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData var_name_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeVarName;
+ var_name_arg.arg_repetition = eArgRepeatPlus;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (var_name_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+ m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_option_format, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_option_compile_units, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_option_shared_libraries, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectTargetVariable ()
+ {
+ }
+
+ void
+ DumpValueObject (Stream &s, VariableSP &var_sp, ValueObjectSP &valobj_sp, const char *root_name)
+ {
+ ValueObject::DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions());
+
+ switch (var_sp->GetScope())
+ {
+ case eValueTypeVariableGlobal:
+ if (m_option_variable.show_scope)
+ s.PutCString("GLOBAL: ");
+ break;
+
+ case eValueTypeVariableStatic:
+ if (m_option_variable.show_scope)
+ s.PutCString("STATIC: ");
+ break;
+
+ case eValueTypeVariableArgument:
+ if (m_option_variable.show_scope)
+ s.PutCString(" ARG: ");
+ break;
+
+ case eValueTypeVariableLocal:
+ if (m_option_variable.show_scope)
+ s.PutCString(" LOCAL: ");
+ break;
+
+ default:
+ break;
+ }
+
+ if (m_option_variable.show_decl)
+ {
+ bool show_fullpaths = false;
+ bool show_module = true;
+ if (var_sp->DumpDeclaration(&s, show_fullpaths, show_module))
+ s.PutCString (": ");
+ }
+
+ const Format format = m_option_format.GetFormat();
+ if (format != eFormatDefault)
+ options.SetFormat(format);
+
+ options.SetRootValueObjectName(root_name);
+
+ ValueObject::DumpValueObject (s,
+ valobj_sp.get(),
+ options);
+
+ }
+
+
+ static size_t GetVariableCallback (void *baton,
+ const char *name,
+ VariableList &variable_list)
+ {
+ Target *target = static_cast<Target *>(baton);
+ if (target)
+ {
+ return target->GetImages().FindGlobalVariables (ConstString(name),
+ true,
+ UINT32_MAX,
+ variable_list);
+ }
+ return 0;
+ }
+
+
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+
+ void
+ DumpGlobalVariableList(const ExecutionContext &exe_ctx, const SymbolContext &sc, const VariableList &variable_list, Stream &s)
+ {
+ size_t count = variable_list.GetSize();
+ if (count > 0)
+ {
+ if (sc.module_sp)
+ {
+ if (sc.comp_unit)
+ {
+ s.Printf ("Global variables for %s in %s:\n",
+ sc.comp_unit->GetPath().c_str(),
+ sc.module_sp->GetFileSpec().GetPath().c_str());
+ }
+ else
+ {
+ s.Printf ("Global variables for %s\n",
+ sc.module_sp->GetFileSpec().GetPath().c_str());
+ }
+ }
+ else if (sc.comp_unit)
+ {
+ s.Printf ("Global variables for %s\n",
+ sc.comp_unit->GetPath().c_str());
+ }
+
+ for (uint32_t i=0; i<count; ++i)
+ {
+ VariableSP var_sp (variable_list.GetVariableAtIndex(i));
+ if (var_sp)
+ {
+ ValueObjectSP valobj_sp (ValueObjectVariable::Create (exe_ctx.GetBestExecutionContextScope(), var_sp));
+
+ if (valobj_sp)
+ DumpValueObject (s, var_sp, valobj_sp, var_sp->GetName().GetCString());
+ }
+ }
+ }
+
+ }
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ const size_t argc = args.GetArgumentCount();
+ Stream &s = result.GetOutputStream();
+
+ if (argc > 0)
+ {
+
+ for (size_t idx = 0; idx < argc; ++idx)
+ {
+ VariableList variable_list;
+ ValueObjectList valobj_list;
+
+ const char *arg = args.GetArgumentAtIndex(idx);
+ size_t matches = 0;
+ bool use_var_name = false;
+ if (m_option_variable.use_regex)
+ {
+ RegularExpression regex(arg);
+ if (!regex.IsValid ())
+ {
+ result.GetErrorStream().Printf ("error: invalid regular expression: '%s'\n", arg);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ use_var_name = true;
+ matches = target->GetImages().FindGlobalVariables (regex,
+ true,
+ UINT32_MAX,
+ variable_list);
+ }
+ else
+ {
+ Error error (Variable::GetValuesForVariableExpressionPath (arg,
+ m_exe_ctx.GetBestExecutionContextScope(),
+ GetVariableCallback,
+ target,
+ variable_list,
+ valobj_list));
+ matches = variable_list.GetSize();
+ }
+
+ if (matches == 0)
+ {
+ result.GetErrorStream().Printf ("error: can't find global variable '%s'\n", arg);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ for (uint32_t global_idx=0; global_idx<matches; ++global_idx)
+ {
+ VariableSP var_sp (variable_list.GetVariableAtIndex(global_idx));
+ if (var_sp)
+ {
+ ValueObjectSP valobj_sp (valobj_list.GetValueObjectAtIndex(global_idx));
+ if (!valobj_sp)
+ valobj_sp = ValueObjectVariable::Create (m_exe_ctx.GetBestExecutionContextScope(), var_sp);
+
+ if (valobj_sp)
+ DumpValueObject (s, var_sp, valobj_sp, use_var_name ? var_sp->GetName().GetCString() : arg);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ const FileSpecList &compile_units = m_option_compile_units.GetOptionValue().GetCurrentValue();
+ const FileSpecList &shlibs = m_option_shared_libraries.GetOptionValue().GetCurrentValue();
+ SymbolContextList sc_list;
+ const size_t num_compile_units = compile_units.GetSize();
+ const size_t num_shlibs = shlibs.GetSize();
+ if (num_compile_units == 0 && num_shlibs == 0)
+ {
+ bool success = false;
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+ CompileUnit *comp_unit = NULL;
+ if (frame)
+ {
+ SymbolContext sc = frame->GetSymbolContext (eSymbolContextCompUnit);
+ if (sc.comp_unit)
+ {
+ const bool can_create = true;
+ VariableListSP comp_unit_varlist_sp (sc.comp_unit->GetVariableList(can_create));
+ if (comp_unit_varlist_sp)
+ {
+ size_t count = comp_unit_varlist_sp->GetSize();
+ if (count > 0)
+ {
+ DumpGlobalVariableList(m_exe_ctx, sc, *comp_unit_varlist_sp, s);
+ success = true;
+ }
+ }
+ }
+ }
+ if (!success)
+ {
+ if (frame)
+ {
+ if (comp_unit)
+ result.AppendErrorWithFormat ("no global variables in current compile unit: %s\n",
+ comp_unit->GetPath().c_str());
+ else
+ result.AppendErrorWithFormat ("no debug information for frame %u\n", frame->GetFrameIndex());
+ }
+ else
+ result.AppendError ("'target variable' takes one or more global variable names as arguments\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ SymbolContextList sc_list;
+ const bool append = true;
+ // We have one or more compile unit or shlib
+ if (num_shlibs > 0)
+ {
+ for (size_t shlib_idx=0; shlib_idx<num_shlibs; ++shlib_idx)
+ {
+ const FileSpec module_file(shlibs.GetFileSpecAtIndex(shlib_idx));
+ ModuleSpec module_spec (module_file);
+
+ ModuleSP module_sp (target->GetImages().FindFirstModule(module_spec));
+ if (module_sp)
+ {
+ if (num_compile_units > 0)
+ {
+ for (size_t cu_idx=0; cu_idx<num_compile_units; ++cu_idx)
+ module_sp->FindCompileUnits(compile_units.GetFileSpecAtIndex(cu_idx), append, sc_list);
+ }
+ else
+ {
+ SymbolContext sc;
+ sc.module_sp = module_sp;
+ sc_list.Append(sc);
+ }
+ }
+ else
+ {
+ // Didn't find matching shlib/module in target...
+ result.AppendErrorWithFormat ("target doesn't contain the specified shared library: %s\n",
+ module_file.GetPath().c_str());
+ }
+ }
+ }
+ else
+ {
+ // No shared libraries, we just want to find globals for the compile units files that were specified
+ for (size_t cu_idx=0; cu_idx<num_compile_units; ++cu_idx)
+ target->GetImages().FindCompileUnits(compile_units.GetFileSpecAtIndex(cu_idx), append, sc_list);
+ }
+
+ const uint32_t num_scs = sc_list.GetSize();
+ if (num_scs > 0)
+ {
+ SymbolContext sc;
+ for (uint32_t sc_idx=0; sc_idx<num_scs; ++sc_idx)
+ {
+ if (sc_list.GetContextAtIndex(sc_idx, sc))
+ {
+ if (sc.comp_unit)
+ {
+ const bool can_create = true;
+ VariableListSP comp_unit_varlist_sp (sc.comp_unit->GetVariableList(can_create));
+ if (comp_unit_varlist_sp)
+ DumpGlobalVariableList(m_exe_ctx, sc, *comp_unit_varlist_sp, s);
+ }
+ else if (sc.module_sp)
+ {
+ // Get all global variables for this module
+ lldb_private::RegularExpression all_globals_regex("."); // Any global with at least one character
+ VariableList variable_list;
+ sc.module_sp->FindGlobalVariables(all_globals_regex, append, UINT32_MAX, variable_list);
+ DumpGlobalVariableList(m_exe_ctx, sc, variable_list, s);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (m_interpreter.TruncationWarningNecessary())
+ {
+ result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
+ m_cmd_name.c_str());
+ m_interpreter.TruncationWarningGiven();
+ }
+
+ return result.Succeeded();
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupVariable m_option_variable;
+ OptionGroupFormat m_option_format;
+ OptionGroupFileList m_option_compile_units;
+ OptionGroupFileList m_option_shared_libraries;
+ OptionGroupValueObjectDisplay m_varobj_options;
+
+};
+
+
+#pragma mark CommandObjectTargetModulesSearchPathsAdd
+
+class CommandObjectTargetModulesSearchPathsAdd : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetModulesSearchPathsAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules search-paths add",
+ "Add new image search paths substitution pairs to the current target.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData old_prefix_arg;
+ CommandArgumentData new_prefix_arg;
+
+ // Define the first variant of this arg pair.
+ old_prefix_arg.arg_type = eArgTypeOldPathPrefix;
+ old_prefix_arg.arg_repetition = eArgRepeatPairPlus;
+
+ // Define the first variant of this arg pair.
+ new_prefix_arg.arg_type = eArgTypeNewPathPrefix;
+ new_prefix_arg.arg_repetition = eArgRepeatPairPlus;
+
+ // There are two required arguments that must always occur together, i.e. an argument "pair". Because they
+ // must always occur together, they are treated as two variants of one argument rather than two independent
+ // arguments. Push them both into the first argument position for m_arguments...
+
+ arg.push_back (old_prefix_arg);
+ arg.push_back (new_prefix_arg);
+
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectTargetModulesSearchPathsAdd ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc & 1)
+ {
+ result.AppendError ("add requires an even number of arguments\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ for (size_t i=0; i<argc; i+=2)
+ {
+ const char *from = command.GetArgumentAtIndex(i);
+ const char *to = command.GetArgumentAtIndex(i+1);
+
+ if (from[0] && to[0])
+ {
+ bool last_pair = ((argc - i) == 2);
+ target->GetImageSearchPathList().Append (ConstString(from),
+ ConstString(to),
+ last_pair); // Notify if this is the last pair
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ if (from[0])
+ result.AppendError ("<path-prefix> can't be empty\n");
+ else
+ result.AppendError ("<new-path-prefix> can't be empty\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+#pragma mark CommandObjectTargetModulesSearchPathsClear
+
+class CommandObjectTargetModulesSearchPathsClear : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetModulesSearchPathsClear (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules search-paths clear",
+ "Clear all current image search path substitution pairs from the current target.",
+ "target modules search-paths clear")
+ {
+ }
+
+ ~CommandObjectTargetModulesSearchPathsClear ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ bool notify = true;
+ target->GetImageSearchPathList().Clear(notify);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+#pragma mark CommandObjectTargetModulesSearchPathsInsert
+
+class CommandObjectTargetModulesSearchPathsInsert : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetModulesSearchPathsInsert (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules search-paths insert",
+ "Insert a new image search path substitution pair into the current target at the specified index.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData index_arg;
+ CommandArgumentData old_prefix_arg;
+ CommandArgumentData new_prefix_arg;
+
+ // Define the first and only variant of this arg.
+ index_arg.arg_type = eArgTypeIndex;
+ index_arg.arg_repetition = eArgRepeatPlain;
+
+ // Put the one and only variant into the first arg for m_arguments:
+ arg1.push_back (index_arg);
+
+ // Define the first variant of this arg pair.
+ old_prefix_arg.arg_type = eArgTypeOldPathPrefix;
+ old_prefix_arg.arg_repetition = eArgRepeatPairPlus;
+
+ // Define the first variant of this arg pair.
+ new_prefix_arg.arg_type = eArgTypeNewPathPrefix;
+ new_prefix_arg.arg_repetition = eArgRepeatPairPlus;
+
+ // There are two required arguments that must always occur together, i.e. an argument "pair". Because they
+ // must always occur together, they are treated as two variants of one argument rather than two independent
+ // arguments. Push them both into the same argument position for m_arguments...
+
+ arg2.push_back (old_prefix_arg);
+ arg2.push_back (new_prefix_arg);
+
+ // Add arguments to m_arguments.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ }
+
+ ~CommandObjectTargetModulesSearchPathsInsert ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ size_t argc = command.GetArgumentCount();
+ // check for at least 3 arguments and an odd nubmer of parameters
+ if (argc >= 3 && argc & 1)
+ {
+ bool success = false;
+
+ uint32_t insert_idx = Args::StringToUInt32(command.GetArgumentAtIndex(0), UINT32_MAX, 0, &success);
+
+ if (!success)
+ {
+ result.AppendErrorWithFormat("<index> parameter is not an integer: '%s'.\n", command.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
+ }
+
+ // shift off the index
+ command.Shift();
+ argc = command.GetArgumentCount();
+
+ for (uint32_t i=0; i<argc; i+=2, ++insert_idx)
+ {
+ const char *from = command.GetArgumentAtIndex(i);
+ const char *to = command.GetArgumentAtIndex(i+1);
+
+ if (from[0] && to[0])
+ {
+ bool last_pair = ((argc - i) == 2);
+ target->GetImageSearchPathList().Insert (ConstString(from),
+ ConstString(to),
+ insert_idx,
+ last_pair);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ if (from[0])
+ result.AppendError ("<path-prefix> can't be empty\n");
+ else
+ result.AppendError ("<new-path-prefix> can't be empty\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ else
+ {
+ result.AppendError ("insert requires at least three arguments\n");
+ result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
+ }
+
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+
+#pragma mark CommandObjectTargetModulesSearchPathsList
+
+
+class CommandObjectTargetModulesSearchPathsList : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetModulesSearchPathsList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules search-paths list",
+ "List all current image search path substitution pairs in the current target.",
+ "target modules search-paths list")
+ {
+ }
+
+ ~CommandObjectTargetModulesSearchPathsList ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ if (command.GetArgumentCount() != 0)
+ {
+ result.AppendError ("list takes no arguments\n");
+ result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
+ }
+
+ target->GetImageSearchPathList().Dump(&result.GetOutputStream());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+#pragma mark CommandObjectTargetModulesSearchPathsQuery
+
+class CommandObjectTargetModulesSearchPathsQuery : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetModulesSearchPathsQuery (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules search-paths query",
+ "Transform a path using the first applicable image search path.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData path_arg;
+
+ // Define the first (and only) variant of this arg.
+ path_arg.arg_type = eArgTypeDirectoryName;
+ path_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (path_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectTargetModulesSearchPathsQuery ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ if (command.GetArgumentCount() != 1)
+ {
+ result.AppendError ("query requires one argument\n");
+ result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
+ }
+
+ ConstString orig(command.GetArgumentAtIndex(0));
+ ConstString transformed;
+ if (target->GetImageSearchPathList().RemapPath(orig, transformed))
+ result.GetOutputStream().Printf("%s\n", transformed.GetCString());
+ else
+ result.GetOutputStream().Printf("%s\n", orig.GetCString());
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+//----------------------------------------------------------------------
+// Static Helper functions
+//----------------------------------------------------------------------
+static void
+DumpModuleArchitecture (Stream &strm, Module *module, bool full_triple, uint32_t width)
+{
+ if (module)
+ {
+ const char *arch_cstr;
+ if (full_triple)
+ arch_cstr = module->GetArchitecture().GetTriple().str().c_str();
+ else
+ arch_cstr = module->GetArchitecture().GetArchitectureName();
+ if (width)
+ strm.Printf("%-*s", width, arch_cstr);
+ else
+ strm.PutCString(arch_cstr);
+ }
+}
+
+static void
+DumpModuleUUID (Stream &strm, Module *module)
+{
+ if (module && module->GetUUID().IsValid())
+ module->GetUUID().Dump (&strm);
+ else
+ strm.PutCString(" ");
+}
+
+static uint32_t
+DumpCompileUnitLineTable (CommandInterpreter &interpreter,
+ Stream &strm,
+ Module *module,
+ const FileSpec &file_spec,
+ bool load_addresses)
+{
+ uint32_t num_matches = 0;
+ if (module)
+ {
+ SymbolContextList sc_list;
+ num_matches = module->ResolveSymbolContextsForFileSpec (file_spec,
+ 0,
+ false,
+ eSymbolContextCompUnit,
+ sc_list);
+
+ for (uint32_t i=0; i<num_matches; ++i)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(i, sc))
+ {
+ if (i > 0)
+ strm << "\n\n";
+
+ strm << "Line table for " << *static_cast<FileSpec*> (sc.comp_unit) << " in `"
+ << module->GetFileSpec().GetFilename() << "\n";
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+ if (line_table)
+ line_table->GetDescription (&strm,
+ interpreter.GetExecutionContext().GetTargetPtr(),
+ lldb::eDescriptionLevelBrief);
+ else
+ strm << "No line table";
+ }
+ }
+ }
+ return num_matches;
+}
+
+static void
+DumpFullpath (Stream &strm, const FileSpec *file_spec_ptr, uint32_t width)
+{
+ if (file_spec_ptr)
+ {
+ if (width > 0)
+ {
+ std::string fullpath = file_spec_ptr->GetPath();
+ strm.Printf("%-*s", width, fullpath.c_str());
+ return;
+ }
+ else
+ {
+ file_spec_ptr->Dump(&strm);
+ return;
+ }
+ }
+ // Keep the width spacing correct if things go wrong...
+ if (width > 0)
+ strm.Printf("%-*s", width, "");
+}
+
+static void
+DumpDirectory (Stream &strm, const FileSpec *file_spec_ptr, uint32_t width)
+{
+ if (file_spec_ptr)
+ {
+ if (width > 0)
+ strm.Printf("%-*s", width, file_spec_ptr->GetDirectory().AsCString(""));
+ else
+ file_spec_ptr->GetDirectory().Dump(&strm);
+ return;
+ }
+ // Keep the width spacing correct if things go wrong...
+ if (width > 0)
+ strm.Printf("%-*s", width, "");
+}
+
+static void
+DumpBasename (Stream &strm, const FileSpec *file_spec_ptr, uint32_t width)
+{
+ if (file_spec_ptr)
+ {
+ if (width > 0)
+ strm.Printf("%-*s", width, file_spec_ptr->GetFilename().AsCString(""));
+ else
+ file_spec_ptr->GetFilename().Dump(&strm);
+ return;
+ }
+ // Keep the width spacing correct if things go wrong...
+ if (width > 0)
+ strm.Printf("%-*s", width, "");
+}
+
+
+static void
+DumpModuleSymtab (CommandInterpreter &interpreter, Stream &strm, Module *module, SortOrder sort_order)
+{
+ if (module)
+ {
+ SymbolVendor *sym_vendor = module->GetSymbolVendor ();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ symtab->Dump(&strm, interpreter.GetExecutionContext().GetTargetPtr(), sort_order);
+ }
+ }
+}
+
+static void
+DumpModuleSections (CommandInterpreter &interpreter, Stream &strm, Module *module)
+{
+ if (module)
+ {
+ SectionList *section_list = module->GetSectionList();
+ if (section_list)
+ {
+ strm.Printf ("Sections for '%s' (%s):\n",
+ module->GetSpecificationDescription().c_str(),
+ module->GetArchitecture().GetArchitectureName());
+ strm.IndentMore();
+ section_list->Dump(&strm, interpreter.GetExecutionContext().GetTargetPtr(), true, UINT32_MAX);
+ strm.IndentLess();
+ }
+ }
+}
+
+static bool
+DumpModuleSymbolVendor (Stream &strm, Module *module)
+{
+ if (module)
+ {
+ SymbolVendor *symbol_vendor = module->GetSymbolVendor(true);
+ if (symbol_vendor)
+ {
+ symbol_vendor->Dump(&strm);
+ return true;
+ }
+ }
+ return false;
+}
+
+static void
+DumpAddress (ExecutionContextScope *exe_scope, const Address &so_addr, bool verbose, Stream &strm)
+{
+ strm.IndentMore();
+ strm.Indent (" Address: ");
+ so_addr.Dump (&strm, exe_scope, Address::DumpStyleModuleWithFileAddress);
+ strm.PutCString (" (");
+ so_addr.Dump (&strm, exe_scope, Address::DumpStyleSectionNameOffset);
+ strm.PutCString (")\n");
+ strm.Indent (" Summary: ");
+ const uint32_t save_indent = strm.GetIndentLevel ();
+ strm.SetIndentLevel (save_indent + 13);
+ so_addr.Dump (&strm, exe_scope, Address::DumpStyleResolvedDescription);
+ strm.SetIndentLevel (save_indent);
+ // Print out detailed address information when verbose is enabled
+ if (verbose)
+ {
+ strm.EOL();
+ so_addr.Dump (&strm, exe_scope, Address::DumpStyleDetailedSymbolContext);
+ }
+ strm.IndentLess();
+}
+
+static bool
+LookupAddressInModule (CommandInterpreter &interpreter,
+ Stream &strm,
+ Module *module,
+ uint32_t resolve_mask,
+ lldb::addr_t raw_addr,
+ lldb::addr_t offset,
+ bool verbose)
+{
+ if (module)
+ {
+ lldb::addr_t addr = raw_addr - offset;
+ Address so_addr;
+ SymbolContext sc;
+ Target *target = interpreter.GetExecutionContext().GetTargetPtr();
+ if (target && !target->GetSectionLoadList().IsEmpty())
+ {
+ if (!target->GetSectionLoadList().ResolveLoadAddress (addr, so_addr))
+ return false;
+ else if (so_addr.GetModule().get() != module)
+ return false;
+ }
+ else
+ {
+ if (!module->ResolveFileAddress (addr, so_addr))
+ return false;
+ }
+
+ ExecutionContextScope *exe_scope = interpreter.GetExecutionContext().GetBestExecutionContextScope();
+ DumpAddress (exe_scope, so_addr, verbose, strm);
+// strm.IndentMore();
+// strm.Indent (" Address: ");
+// so_addr.Dump (&strm, exe_scope, Address::DumpStyleModuleWithFileAddress);
+// strm.PutCString (" (");
+// so_addr.Dump (&strm, exe_scope, Address::DumpStyleSectionNameOffset);
+// strm.PutCString (")\n");
+// strm.Indent (" Summary: ");
+// const uint32_t save_indent = strm.GetIndentLevel ();
+// strm.SetIndentLevel (save_indent + 13);
+// so_addr.Dump (&strm, exe_scope, Address::DumpStyleResolvedDescription);
+// strm.SetIndentLevel (save_indent);
+// // Print out detailed address information when verbose is enabled
+// if (verbose)
+// {
+// strm.EOL();
+// so_addr.Dump (&strm, exe_scope, Address::DumpStyleDetailedSymbolContext);
+// }
+// strm.IndentLess();
+ return true;
+ }
+
+ return false;
+}
+
+static uint32_t
+LookupSymbolInModule (CommandInterpreter &interpreter, Stream &strm, Module *module, const char *name, bool name_is_regex, bool verbose)
+{
+ if (module)
+ {
+ SymbolContext sc;
+
+ SymbolVendor *sym_vendor = module->GetSymbolVendor ();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ {
+ uint32_t i;
+ std::vector<uint32_t> match_indexes;
+ ConstString symbol_name (name);
+ uint32_t num_matches = 0;
+ if (name_is_regex)
+ {
+ RegularExpression name_regexp(name);
+ num_matches = symtab->AppendSymbolIndexesMatchingRegExAndType (name_regexp,
+ eSymbolTypeAny,
+ match_indexes);
+ }
+ else
+ {
+ num_matches = symtab->AppendSymbolIndexesWithName (symbol_name, match_indexes);
+ }
+
+
+ if (num_matches > 0)
+ {
+ strm.Indent ();
+ strm.Printf("%u symbols match %s'%s' in ", num_matches,
+ name_is_regex ? "the regular expression " : "", name);
+ DumpFullpath (strm, &module->GetFileSpec(), 0);
+ strm.PutCString(":\n");
+ strm.IndentMore ();
+ //Symtab::DumpSymbolHeader (&strm);
+ for (i=0; i < num_matches; ++i)
+ {
+ Symbol *symbol = symtab->SymbolAtIndex(match_indexes[i]);
+ DumpAddress (interpreter.GetExecutionContext().GetBestExecutionContextScope(),
+ symbol->GetAddress(),
+ verbose,
+ strm);
+
+// strm.Indent ();
+// symbol->Dump (&strm, interpreter.GetExecutionContext().GetTargetPtr(), i);
+ }
+ strm.IndentLess ();
+ return num_matches;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+static void
+DumpSymbolContextList (ExecutionContextScope *exe_scope, Stream &strm, SymbolContextList &sc_list, bool verbose)
+{
+ strm.IndentMore ();
+ uint32_t i;
+ const uint32_t num_matches = sc_list.GetSize();
+
+ for (i=0; i<num_matches; ++i)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(i, sc))
+ {
+ AddressRange range;
+
+ sc.GetAddressRange(eSymbolContextEverything,
+ 0,
+ true,
+ range);
+
+ DumpAddress (exe_scope, range.GetBaseAddress(), verbose, strm);
+ }
+ }
+ strm.IndentLess ();
+}
+
+static size_t
+LookupFunctionInModule (CommandInterpreter &interpreter,
+ Stream &strm,
+ Module *module,
+ const char *name,
+ bool name_is_regex,
+ bool include_inlines,
+ bool include_symbols,
+ bool verbose)
+{
+ if (module && name && name[0])
+ {
+ SymbolContextList sc_list;
+ const bool append = true;
+ size_t num_matches = 0;
+ if (name_is_regex)
+ {
+ RegularExpression function_name_regex (name);
+ num_matches = module->FindFunctions (function_name_regex,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ }
+ else
+ {
+ ConstString function_name (name);
+ num_matches = module->FindFunctions (function_name,
+ NULL,
+ eFunctionNameTypeAuto,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ }
+
+ if (num_matches)
+ {
+ strm.Indent ();
+ strm.Printf("%zu match%s found in ", num_matches, num_matches > 1 ? "es" : "");
+ DumpFullpath (strm, &module->GetFileSpec(), 0);
+ strm.PutCString(":\n");
+ DumpSymbolContextList (interpreter.GetExecutionContext().GetBestExecutionContextScope(), strm, sc_list, verbose);
+ }
+ return num_matches;
+ }
+ return 0;
+}
+
+static size_t
+LookupTypeInModule (CommandInterpreter &interpreter,
+ Stream &strm,
+ Module *module,
+ const char *name_cstr,
+ bool name_is_regex)
+{
+ if (module && name_cstr && name_cstr[0])
+ {
+ TypeList type_list;
+ const uint32_t max_num_matches = UINT32_MAX;
+ size_t num_matches = 0;
+ bool name_is_fully_qualified = false;
+ SymbolContext sc;
+
+ ConstString name(name_cstr);
+ num_matches = module->FindTypes(sc, name, name_is_fully_qualified, max_num_matches, type_list);
+
+ if (num_matches)
+ {
+ strm.Indent ();
+ strm.Printf("%zu match%s found in ", num_matches, num_matches > 1 ? "es" : "");
+ DumpFullpath (strm, &module->GetFileSpec(), 0);
+ strm.PutCString(":\n");
+ const uint32_t num_types = type_list.GetSize();
+ for (uint32_t i=0; i<num_types; ++i)
+ {
+ TypeSP type_sp (type_list.GetTypeAtIndex(i));
+ if (type_sp)
+ {
+ // Resolve the clang type so that any forward references
+ // to types that haven't yet been parsed will get parsed.
+ type_sp->GetClangFullType ();
+ type_sp->GetDescription (&strm, eDescriptionLevelFull, true);
+ // Print all typedef chains
+ TypeSP typedef_type_sp (type_sp);
+ TypeSP typedefed_type_sp (typedef_type_sp->GetTypedefType());
+ while (typedefed_type_sp)
+ {
+ strm.EOL();
+ strm.Printf(" typedef '%s': ", typedef_type_sp->GetName().GetCString());
+ typedefed_type_sp->GetClangFullType ();
+ typedefed_type_sp->GetDescription (&strm, eDescriptionLevelFull, true);
+ typedef_type_sp = typedefed_type_sp;
+ typedefed_type_sp = typedef_type_sp->GetTypedefType();
+ }
+ }
+ strm.EOL();
+ }
+ }
+ return num_matches;
+ }
+ return 0;
+}
+
+static size_t
+LookupTypeHere (CommandInterpreter &interpreter,
+ Stream &strm,
+ const SymbolContext &sym_ctx,
+ const char *name_cstr,
+ bool name_is_regex)
+{
+ if (!sym_ctx.module_sp)
+ return 0;
+
+ TypeList type_list;
+ const uint32_t max_num_matches = UINT32_MAX;
+ size_t num_matches = 1;
+ bool name_is_fully_qualified = false;
+
+ ConstString name(name_cstr);
+ num_matches = sym_ctx.module_sp->FindTypes(sym_ctx, name, name_is_fully_qualified, max_num_matches, type_list);
+
+ if (num_matches)
+ {
+ strm.Indent ();
+ strm.PutCString("Best match found in ");
+ DumpFullpath (strm, &sym_ctx.module_sp->GetFileSpec(), 0);
+ strm.PutCString(":\n");
+
+ TypeSP type_sp (type_list.GetTypeAtIndex(0));
+ if (type_sp)
+ {
+ // Resolve the clang type so that any forward references
+ // to types that haven't yet been parsed will get parsed.
+ type_sp->GetClangFullType ();
+ type_sp->GetDescription (&strm, eDescriptionLevelFull, true);
+ // Print all typedef chains
+ TypeSP typedef_type_sp (type_sp);
+ TypeSP typedefed_type_sp (typedef_type_sp->GetTypedefType());
+ while (typedefed_type_sp)
+ {
+ strm.EOL();
+ strm.Printf(" typedef '%s': ", typedef_type_sp->GetName().GetCString());
+ typedefed_type_sp->GetClangFullType ();
+ typedefed_type_sp->GetDescription (&strm, eDescriptionLevelFull, true);
+ typedef_type_sp = typedefed_type_sp;
+ typedefed_type_sp = typedef_type_sp->GetTypedefType();
+ }
+ }
+ strm.EOL();
+ }
+ return num_matches;
+}
+
+static uint32_t
+LookupFileAndLineInModule (CommandInterpreter &interpreter,
+ Stream &strm,
+ Module *module,
+ const FileSpec &file_spec,
+ uint32_t line,
+ bool check_inlines,
+ bool verbose)
+{
+ if (module && file_spec)
+ {
+ SymbolContextList sc_list;
+ const uint32_t num_matches = module->ResolveSymbolContextsForFileSpec(file_spec, line, check_inlines,
+ eSymbolContextEverything, sc_list);
+ if (num_matches > 0)
+ {
+ strm.Indent ();
+ strm.Printf("%u match%s found in ", num_matches, num_matches > 1 ? "es" : "");
+ strm << file_spec;
+ if (line > 0)
+ strm.Printf (":%u", line);
+ strm << " in ";
+ DumpFullpath (strm, &module->GetFileSpec(), 0);
+ strm.PutCString(":\n");
+ DumpSymbolContextList (interpreter.GetExecutionContext().GetBestExecutionContextScope(), strm, sc_list, verbose);
+ return num_matches;
+ }
+ }
+ return 0;
+
+}
+
+
+static size_t
+FindModulesByName (Target *target,
+ const char *module_name,
+ ModuleList &module_list,
+ bool check_global_list)
+{
+// Dump specified images (by basename or fullpath)
+ FileSpec module_file_spec(module_name, false);
+ ModuleSpec module_spec (module_file_spec);
+
+ const size_t initial_size = module_list.GetSize ();
+
+ if (check_global_list)
+ {
+ // Check the global list
+ Mutex::Locker locker(Module::GetAllocationModuleCollectionMutex());
+ const size_t num_modules = Module::GetNumberAllocatedModules();
+ ModuleSP module_sp;
+ for (size_t image_idx = 0; image_idx<num_modules; ++image_idx)
+ {
+ Module *module = Module::GetAllocatedModuleAtIndex(image_idx);
+
+ if (module)
+ {
+ if (module->MatchesModuleSpec (module_spec))
+ {
+ module_sp = module->shared_from_this();
+ module_list.AppendIfNeeded(module_sp);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (target)
+ {
+ const size_t num_matches = target->GetImages().FindModules (module_spec, module_list);
+
+ // Not found in our module list for our target, check the main
+ // shared module list in case it is a extra file used somewhere
+ // else
+ if (num_matches == 0)
+ {
+ module_spec.GetArchitecture() = target->GetArchitecture();
+ ModuleList::FindSharedModules (module_spec, module_list);
+ }
+ }
+ else
+ {
+ ModuleList::FindSharedModules (module_spec,module_list);
+ }
+ }
+
+ return module_list.GetSize () - initial_size;
+}
+
+#pragma mark CommandObjectTargetModulesModuleAutoComplete
+
+//----------------------------------------------------------------------
+// A base command object class that can auto complete with module file
+// paths
+//----------------------------------------------------------------------
+
+class CommandObjectTargetModulesModuleAutoComplete : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetModulesModuleAutoComplete (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax) :
+ CommandObjectParsed (interpreter, name, help, syntax)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData file_arg;
+
+ // Define the first (and only) variant of this arg.
+ file_arg.arg_type = eArgTypeFilename;
+ file_arg.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (file_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectTargetModulesModuleAutoComplete ()
+ {
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ // Arguments are the standard module completer.
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eModuleCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+};
+
+#pragma mark CommandObjectTargetModulesSourceFileAutoComplete
+
+//----------------------------------------------------------------------
+// A base command object class that can auto complete with module source
+// file paths
+//----------------------------------------------------------------------
+
+class CommandObjectTargetModulesSourceFileAutoComplete : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetModulesSourceFileAutoComplete (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t flags) :
+ CommandObjectParsed (interpreter, name, help, syntax, flags)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData source_file_arg;
+
+ // Define the first (and only) variant of this arg.
+ source_file_arg.arg_type = eArgTypeSourceFile;
+ source_file_arg.arg_repetition = eArgRepeatPlus;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (source_file_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectTargetModulesSourceFileAutoComplete ()
+ {
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ // Arguments are the standard source file completer.
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSourceFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+};
+
+
+#pragma mark CommandObjectTargetModulesDumpSymtab
+
+
+class CommandObjectTargetModulesDumpSymtab : public CommandObjectTargetModulesModuleAutoComplete
+{
+public:
+ CommandObjectTargetModulesDumpSymtab (CommandInterpreter &interpreter) :
+ CommandObjectTargetModulesModuleAutoComplete (interpreter,
+ "target modules dump symtab",
+ "Dump the symbol table from one or more target modules.",
+ NULL),
+ m_options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetModulesDumpSymtab ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter),
+ m_sort_order (eSortOrderNone)
+ {
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 's':
+ m_sort_order = (SortOrder) Args::StringToOptionEnum (option_arg,
+ g_option_table[option_idx].enum_values,
+ eSortOrderNone,
+ error);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_sort_order = eSortOrderNone;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+ static OptionDefinition g_option_table[];
+
+ SortOrder m_sort_order;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ uint32_t num_dumped = 0;
+
+ uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
+ result.GetOutputStream().SetAddressByteSize(addr_byte_size);
+ result.GetErrorStream().SetAddressByteSize(addr_byte_size);
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // Dump all sections for all modules images
+ Mutex::Locker modules_locker(target->GetImages().GetMutex());
+ const size_t num_modules = target->GetImages().GetSize();
+ if (num_modules > 0)
+ {
+ result.GetOutputStream().Printf("Dumping symbol table for %zu modules.\n", num_modules);
+ for (size_t image_idx = 0; image_idx<num_modules; ++image_idx)
+ {
+ if (num_dumped > 0)
+ {
+ result.GetOutputStream().EOL();
+ result.GetOutputStream().EOL();
+ }
+ num_dumped++;
+ DumpModuleSymtab (m_interpreter,
+ result.GetOutputStream(),
+ target->GetImages().GetModulePointerAtIndexUnlocked(image_idx),
+ m_options.m_sort_order);
+ }
+ }
+ else
+ {
+ result.AppendError ("the target has no associated executable images");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ // Dump specified images (by basename or fullpath)
+ const char *arg_cstr;
+ for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx)
+ {
+ ModuleList module_list;
+ const size_t num_matches = FindModulesByName (target, arg_cstr, module_list, true);
+ if (num_matches > 0)
+ {
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ Module *module = module_list.GetModulePointerAtIndex(i);
+ if (module)
+ {
+ if (num_dumped > 0)
+ {
+ result.GetOutputStream().EOL();
+ result.GetOutputStream().EOL();
+ }
+ num_dumped++;
+ DumpModuleSymtab (m_interpreter, result.GetOutputStream(), module, m_options.m_sort_order);
+ }
+ }
+ }
+ else
+ result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr);
+ }
+ }
+
+ if (num_dumped > 0)
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ else
+ {
+ result.AppendError ("no matching executable images found");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ return result.Succeeded();
+ }
+
+
+ CommandOptions m_options;
+};
+
+static OptionEnumValueElement
+g_sort_option_enumeration[4] =
+{
+ { eSortOrderNone, "none", "No sorting, use the original symbol table order."},
+ { eSortOrderByAddress, "address", "Sort output by symbol address."},
+ { eSortOrderByName, "name", "Sort output by symbol name."},
+ { 0, NULL, NULL }
+};
+
+
+OptionDefinition
+CommandObjectTargetModulesDumpSymtab::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "sort", 's', required_argument, g_sort_option_enumeration, 0, eArgTypeSortOrder, "Supply a sort order when dumping the symbol table."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#pragma mark CommandObjectTargetModulesDumpSections
+
+//----------------------------------------------------------------------
+// Image section dumping command
+//----------------------------------------------------------------------
+
+class CommandObjectTargetModulesDumpSections : public CommandObjectTargetModulesModuleAutoComplete
+{
+public:
+ CommandObjectTargetModulesDumpSections (CommandInterpreter &interpreter) :
+ CommandObjectTargetModulesModuleAutoComplete (interpreter,
+ "target modules dump sections",
+ "Dump the sections from one or more target modules.",
+ //"target modules dump sections [<file1> ...]")
+ NULL)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetModulesDumpSections ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ uint32_t num_dumped = 0;
+
+ uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
+ result.GetOutputStream().SetAddressByteSize(addr_byte_size);
+ result.GetErrorStream().SetAddressByteSize(addr_byte_size);
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // Dump all sections for all modules images
+ const size_t num_modules = target->GetImages().GetSize();
+ if (num_modules > 0)
+ {
+ result.GetOutputStream().Printf("Dumping sections for %zu modules.\n", num_modules);
+ for (size_t image_idx = 0; image_idx<num_modules; ++image_idx)
+ {
+ num_dumped++;
+ DumpModuleSections (m_interpreter, result.GetOutputStream(), target->GetImages().GetModulePointerAtIndex(image_idx));
+ }
+ }
+ else
+ {
+ result.AppendError ("the target has no associated executable images");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ // Dump specified images (by basename or fullpath)
+ const char *arg_cstr;
+ for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx)
+ {
+ ModuleList module_list;
+ const size_t num_matches = FindModulesByName (target, arg_cstr, module_list, true);
+ if (num_matches > 0)
+ {
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ Module *module = module_list.GetModulePointerAtIndex(i);
+ if (module)
+ {
+ num_dumped++;
+ DumpModuleSections (m_interpreter, result.GetOutputStream(), module);
+ }
+ }
+ }
+ else
+ {
+ // Check the global list
+ Mutex::Locker locker(Module::GetAllocationModuleCollectionMutex());
+
+ result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr);
+ }
+ }
+ }
+
+ if (num_dumped > 0)
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ else
+ {
+ result.AppendError ("no matching executable images found");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+
+#pragma mark CommandObjectTargetModulesDumpSymfile
+
+//----------------------------------------------------------------------
+// Image debug symbol dumping command
+//----------------------------------------------------------------------
+
+class CommandObjectTargetModulesDumpSymfile : public CommandObjectTargetModulesModuleAutoComplete
+{
+public:
+ CommandObjectTargetModulesDumpSymfile (CommandInterpreter &interpreter) :
+ CommandObjectTargetModulesModuleAutoComplete (interpreter,
+ "target modules dump symfile",
+ "Dump the debug symbol file for one or more target modules.",
+ //"target modules dump symfile [<file1> ...]")
+ NULL)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetModulesDumpSymfile ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ uint32_t num_dumped = 0;
+
+ uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
+ result.GetOutputStream().SetAddressByteSize(addr_byte_size);
+ result.GetErrorStream().SetAddressByteSize(addr_byte_size);
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // Dump all sections for all modules images
+ const ModuleList &target_modules = target->GetImages();
+ Mutex::Locker modules_locker (target_modules.GetMutex());
+ const size_t num_modules = target_modules.GetSize();
+ if (num_modules > 0)
+ {
+ result.GetOutputStream().Printf("Dumping debug symbols for %zu modules.\n", num_modules);
+ for (uint32_t image_idx = 0; image_idx<num_modules; ++image_idx)
+ {
+ if (DumpModuleSymbolVendor (result.GetOutputStream(), target_modules.GetModulePointerAtIndexUnlocked(image_idx)))
+ num_dumped++;
+ }
+ }
+ else
+ {
+ result.AppendError ("the target has no associated executable images");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ // Dump specified images (by basename or fullpath)
+ const char *arg_cstr;
+ for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx)
+ {
+ ModuleList module_list;
+ const size_t num_matches = FindModulesByName (target, arg_cstr, module_list, true);
+ if (num_matches > 0)
+ {
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ Module *module = module_list.GetModulePointerAtIndex(i);
+ if (module)
+ {
+ if (DumpModuleSymbolVendor (result.GetOutputStream(), module))
+ num_dumped++;
+ }
+ }
+ }
+ else
+ result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr);
+ }
+ }
+
+ if (num_dumped > 0)
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ else
+ {
+ result.AppendError ("no matching executable images found");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+
+#pragma mark CommandObjectTargetModulesDumpLineTable
+
+//----------------------------------------------------------------------
+// Image debug line table dumping command
+//----------------------------------------------------------------------
+
+class CommandObjectTargetModulesDumpLineTable : public CommandObjectTargetModulesSourceFileAutoComplete
+{
+public:
+ CommandObjectTargetModulesDumpLineTable (CommandInterpreter &interpreter) :
+ CommandObjectTargetModulesSourceFileAutoComplete (interpreter,
+ "target modules dump line-table",
+ "Dump the line table for one or more compilation units.",
+ NULL,
+ eFlagRequiresTarget)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetModulesDumpLineTable ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ uint32_t total_num_dumped = 0;
+
+ uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
+ result.GetOutputStream().SetAddressByteSize(addr_byte_size);
+ result.GetErrorStream().SetAddressByteSize(addr_byte_size);
+
+ if (command.GetArgumentCount() == 0)
+ {
+ result.AppendErrorWithFormat ("\nSyntax: %s\n", m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ // Dump specified images (by basename or fullpath)
+ const char *arg_cstr;
+ for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx)
+ {
+ FileSpec file_spec(arg_cstr, false);
+
+ const ModuleList &target_modules = target->GetImages();
+ Mutex::Locker modules_locker(target_modules.GetMutex());
+ const size_t num_modules = target_modules.GetSize();
+ if (num_modules > 0)
+ {
+ uint32_t num_dumped = 0;
+ for (uint32_t i = 0; i<num_modules; ++i)
+ {
+ if (DumpCompileUnitLineTable (m_interpreter,
+ result.GetOutputStream(),
+ target_modules.GetModulePointerAtIndexUnlocked(i),
+ file_spec,
+ m_exe_ctx.GetProcessPtr() && m_exe_ctx.GetProcessRef().IsAlive()))
+ num_dumped++;
+ }
+ if (num_dumped == 0)
+ result.AppendWarningWithFormat ("No source filenames matched '%s'.\n", arg_cstr);
+ else
+ total_num_dumped += num_dumped;
+ }
+ }
+ }
+
+ if (total_num_dumped > 0)
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ else
+ {
+ result.AppendError ("no source filenames matched any command arguments");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+
+#pragma mark CommandObjectTargetModulesDump
+
+//----------------------------------------------------------------------
+// Dump multi-word command for target modules
+//----------------------------------------------------------------------
+
+class CommandObjectTargetModulesDump : public CommandObjectMultiword
+{
+public:
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectTargetModulesDump(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "target modules dump",
+ "A set of commands for dumping information about one or more target modules.",
+ "target modules dump [symtab|sections|symfile|line-table] [<file1> <file2> ...]")
+ {
+ LoadSubCommand ("symtab", CommandObjectSP (new CommandObjectTargetModulesDumpSymtab (interpreter)));
+ LoadSubCommand ("sections", CommandObjectSP (new CommandObjectTargetModulesDumpSections (interpreter)));
+ LoadSubCommand ("symfile", CommandObjectSP (new CommandObjectTargetModulesDumpSymfile (interpreter)));
+ LoadSubCommand ("line-table", CommandObjectSP (new CommandObjectTargetModulesDumpLineTable (interpreter)));
+ }
+
+ virtual
+ ~CommandObjectTargetModulesDump()
+ {
+ }
+};
+
+class CommandObjectTargetModulesAdd : public CommandObjectParsed
+{
+public:
+ CommandObjectTargetModulesAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules add",
+ "Add a new module to the current target's modules.",
+ "target modules add [<module>]"),
+ m_option_group (interpreter),
+ m_symbol_file (LLDB_OPT_SET_1, false, "symfile", 's', 0, eArgTypeFilename, "Fullpath to a stand alone debug symbols file for when debug symbols are not in the executable.")
+ {
+ m_option_group.Append (&m_uuid_option_group, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_symbol_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectTargetModulesAdd ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eDiskFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+protected:
+
+ OptionGroupOptions m_option_group;
+ OptionGroupUUID m_uuid_option_group;
+ OptionGroupFile m_symbol_file;
+
+
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ bool flush = false;
+
+ const size_t argc = args.GetArgumentCount();
+ if (argc == 0)
+ {
+ if (m_uuid_option_group.GetOptionValue ().OptionWasSet())
+ {
+ // We are given a UUID only, go locate the file
+ ModuleSpec module_spec;
+ module_spec.GetUUID() = m_uuid_option_group.GetOptionValue ().GetCurrentValue();
+ if (m_symbol_file.GetOptionValue().OptionWasSet())
+ module_spec.GetSymbolFileSpec() = m_symbol_file.GetOptionValue().GetCurrentValue();
+ if (Symbols::DownloadObjectAndSymbolFile (module_spec))
+ {
+ ModuleSP module_sp (target->GetSharedModule (module_spec));
+ if (module_sp)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ else
+ {
+ flush = true;
+
+ StreamString strm;
+ module_spec.GetUUID().Dump (&strm);
+ if (module_spec.GetFileSpec())
+ {
+ if (module_spec.GetSymbolFileSpec())
+ {
+ result.AppendErrorWithFormat ("Unable to create the executable or symbol file with UUID %s with path %s and symbol file %s",
+ strm.GetString().c_str(),
+ module_spec.GetFileSpec().GetPath().c_str(),
+ module_spec.GetSymbolFileSpec().GetPath().c_str());
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Unable to create the executable or symbol file with UUID %s with path %s",
+ strm.GetString().c_str(),
+ module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Unable to create the executable or symbol file with UUID %s",
+ strm.GetString().c_str());
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ StreamString strm;
+ module_spec.GetUUID().Dump (&strm);
+ result.AppendErrorWithFormat ("Unable to locate the executable or symbol file with UUID %s", strm.GetString().c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendError ("one or more executable image paths must be specified");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ for (size_t i=0; i<argc; ++i)
+ {
+ const char *path = args.GetArgumentAtIndex(i);
+ if (path)
+ {
+ FileSpec file_spec(path, true);
+ if (file_spec.Exists())
+ {
+ ModuleSpec module_spec (file_spec);
+ if (m_uuid_option_group.GetOptionValue ().OptionWasSet())
+ module_spec.GetUUID() = m_uuid_option_group.GetOptionValue ().GetCurrentValue();
+ if (m_symbol_file.GetOptionValue().OptionWasSet())
+ module_spec.GetSymbolFileSpec() = m_symbol_file.GetOptionValue().GetCurrentValue();
+ Error error;
+ ModuleSP module_sp (target->GetSharedModule (module_spec, &error));
+ if (!module_sp)
+ {
+ const char *error_cstr = error.AsCString();
+ if (error_cstr)
+ result.AppendError (error_cstr);
+ else
+ result.AppendErrorWithFormat ("unsupported module: %s", path);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ flush = true;
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ char resolved_path[PATH_MAX];
+ result.SetStatus (eReturnStatusFailed);
+ if (file_spec.GetPath (resolved_path, sizeof(resolved_path)))
+ {
+ if (strcmp (resolved_path, path) != 0)
+ {
+ result.AppendErrorWithFormat ("invalid module path '%s' with resolved path '%s'\n", path, resolved_path);
+ break;
+ }
+ }
+ result.AppendErrorWithFormat ("invalid module path '%s'\n", path);
+ break;
+ }
+ }
+ }
+ }
+
+ if (flush)
+ {
+ ProcessSP process = target->GetProcessSP();
+ if (process)
+ process->Flush();
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+};
+
+class CommandObjectTargetModulesLoad : public CommandObjectTargetModulesModuleAutoComplete
+{
+public:
+ CommandObjectTargetModulesLoad (CommandInterpreter &interpreter) :
+ CommandObjectTargetModulesModuleAutoComplete (interpreter,
+ "target modules load",
+ "Set the load addresses for one or more sections in a target module.",
+ "target modules load [--file <module> --uuid <uuid>] <sect-name> <address> [<sect-name> <address> ....]"),
+ m_option_group (interpreter),
+ m_file_option (LLDB_OPT_SET_1, false, "file", 'f', 0, eArgTypeFilename, "Fullpath or basename for module to load."),
+ m_slide_option(LLDB_OPT_SET_1, false, "slide", 's', 0, eArgTypeOffset, "Set the load address for all sections to be the virtual address in the file plus the offset.", 0)
+ {
+ m_option_group.Append (&m_uuid_option_group, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_file_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_slide_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectTargetModulesLoad ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ const size_t argc = args.GetArgumentCount();
+ ModuleSpec module_spec;
+ bool search_using_module_spec = false;
+ if (m_file_option.GetOptionValue().OptionWasSet())
+ {
+ search_using_module_spec = true;
+ module_spec.GetFileSpec() = m_file_option.GetOptionValue().GetCurrentValue();
+ }
+
+ if (m_uuid_option_group.GetOptionValue().OptionWasSet())
+ {
+ search_using_module_spec = true;
+ module_spec.GetUUID() = m_uuid_option_group.GetOptionValue().GetCurrentValue();
+ }
+
+ if (search_using_module_spec)
+ {
+
+ ModuleList matching_modules;
+ const size_t num_matches = target->GetImages().FindModules (module_spec, matching_modules);
+
+ char path[PATH_MAX];
+ if (num_matches == 1)
+ {
+ Module *module = matching_modules.GetModulePointerAtIndex(0);
+ if (module)
+ {
+ ObjectFile *objfile = module->GetObjectFile();
+ if (objfile)
+ {
+ SectionList *section_list = module->GetSectionList();
+ if (section_list)
+ {
+ bool changed = false;
+ if (argc == 0)
+ {
+ if (m_slide_option.GetOptionValue().OptionWasSet())
+ {
+ const addr_t slide = m_slide_option.GetOptionValue().GetCurrentValue();
+ module->SetLoadAddress (*target, slide, changed);
+ }
+ else
+ {
+ result.AppendError ("one or more section name + load address pair must be specified");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ if (m_slide_option.GetOptionValue().OptionWasSet())
+ {
+ result.AppendError ("The \"--slide <offset>\" option can't be used in conjunction with setting section load addresses.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ for (size_t i=0; i<argc; i += 2)
+ {
+ const char *sect_name = args.GetArgumentAtIndex(i);
+ const char *load_addr_cstr = args.GetArgumentAtIndex(i+1);
+ if (sect_name && load_addr_cstr)
+ {
+ ConstString const_sect_name(sect_name);
+ bool success = false;
+ addr_t load_addr = Args::StringToUInt64(load_addr_cstr, LLDB_INVALID_ADDRESS, 0, &success);
+ if (success)
+ {
+ SectionSP section_sp (section_list->FindSectionByName(const_sect_name));
+ if (section_sp)
+ {
+ if (section_sp->IsThreadSpecific())
+ {
+ result.AppendErrorWithFormat ("thread specific sections are not yet supported (section '%s')\n", sect_name);
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ else
+ {
+ if (target->GetSectionLoadList().SetSectionLoadAddress (section_sp, load_addr))
+ changed = true;
+ result.AppendMessageWithFormat("section '%s' loaded at 0x%" PRIx64 "\n", sect_name, load_addr);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no section found that matches the section name '%s'\n", sect_name);
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("invalid load address string '%s'\n", load_addr_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ else
+ {
+ if (sect_name)
+ result.AppendError ("section names must be followed by a load address.\n");
+ else
+ result.AppendError ("one or more section name + load address pair must be specified.\n");
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ }
+
+ if (changed)
+ {
+ target->ModulesDidLoad (matching_modules);
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process)
+ process->Flush();
+ }
+ }
+ else
+ {
+ module->GetFileSpec().GetPath (path, sizeof(path));
+ result.AppendErrorWithFormat ("no sections in object file '%s'\n", path);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ module->GetFileSpec().GetPath (path, sizeof(path));
+ result.AppendErrorWithFormat ("no object file for module '%s'\n", path);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ FileSpec *module_spec_file = module_spec.GetFileSpecPtr();
+ if (module_spec_file)
+ {
+ module_spec_file->GetPath (path, sizeof(path));
+ result.AppendErrorWithFormat ("invalid module '%s'.\n", path);
+ }
+ else
+ result.AppendError ("no module spec");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ std::string uuid_str;
+
+ if (module_spec.GetFileSpec())
+ module_spec.GetFileSpec().GetPath (path, sizeof(path));
+ else
+ path[0] = '\0';
+
+ if (module_spec.GetUUIDPtr())
+ uuid_str = module_spec.GetUUID().GetAsString();
+ if (num_matches > 1)
+ {
+ result.AppendErrorWithFormat ("multiple modules match%s%s%s%s:\n",
+ path[0] ? " file=" : "",
+ path,
+ !uuid_str.empty() ? " uuid=" : "",
+ uuid_str.c_str());
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ if (matching_modules.GetModulePointerAtIndex(i)->GetFileSpec().GetPath (path, sizeof(path)))
+ result.AppendMessageWithFormat("%s\n", path);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no modules were found that match%s%s%s%s.\n",
+ path[0] ? " file=" : "",
+ path,
+ !uuid_str.empty() ? " uuid=" : "",
+ uuid_str.c_str());
+ }
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("either the \"--file <module>\" or the \"--uuid <uuid>\" option must be specified.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ return result.Succeeded();
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupUUID m_uuid_option_group;
+ OptionGroupFile m_file_option;
+ OptionGroupUInt64 m_slide_option;
+};
+
+//----------------------------------------------------------------------
+// List images with associated information
+//----------------------------------------------------------------------
+class CommandObjectTargetModulesList : public CommandObjectParsed
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter),
+ m_format_array(),
+ m_use_global_module_list (false),
+ m_module_addr (LLDB_INVALID_ADDRESS)
+ {
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+
+ const int short_option = m_getopt_table[option_idx].val;
+ if (short_option == 'g')
+ {
+ m_use_global_module_list = true;
+ }
+ else if (short_option == 'a')
+ {
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ m_module_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ }
+ else
+ {
+ unsigned long width = 0;
+ if (option_arg)
+ width = strtoul (option_arg, NULL, 0);
+ m_format_array.push_back(std::make_pair(short_option, width));
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_format_array.clear();
+ m_use_global_module_list = false;
+ m_module_addr = LLDB_INVALID_ADDRESS;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ typedef std::vector< std::pair<char, uint32_t> > FormatWidthCollection;
+ FormatWidthCollection m_format_array;
+ bool m_use_global_module_list;
+ lldb::addr_t m_module_addr;
+ };
+
+ CommandObjectTargetModulesList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules list",
+ "List current executable and dependent shared library images.",
+ "target modules list [<cmd-options>]"),
+ m_options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetModulesList ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ const bool use_global_module_list = m_options.m_use_global_module_list;
+ // Define a local module list here to ensure it lives longer than any "locker"
+ // object which might lock its contents below (through the "module_list_ptr"
+ // variable).
+ ModuleList module_list;
+ if (target == NULL && use_global_module_list == false)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ if (target)
+ {
+ uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
+ result.GetOutputStream().SetAddressByteSize(addr_byte_size);
+ result.GetErrorStream().SetAddressByteSize(addr_byte_size);
+ }
+ // Dump all sections for all modules images
+ Stream &strm = result.GetOutputStream();
+
+ if (m_options.m_module_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (target)
+ {
+ Address module_address;
+ if (module_address.SetLoadAddress(m_options.m_module_addr, target))
+ {
+ ModuleSP module_sp (module_address.GetModule());
+ if (module_sp)
+ {
+ PrintModule (target, module_sp.get(), 0, strm);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Couldn't find module matching address: 0x%" PRIx64 ".", m_options.m_module_addr);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Couldn't find module containing address: 0x%" PRIx64 ".", m_options.m_module_addr);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("Can only look up modules by address with a valid target.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ size_t num_modules = 0;
+ Mutex::Locker locker; // This locker will be locked on the mutex in module_list_ptr if it is non-NULL.
+ // Otherwise it will lock the AllocationModuleCollectionMutex when accessing
+ // the global module list directly.
+ const ModuleList *module_list_ptr = NULL;
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ if (use_global_module_list)
+ {
+ locker.Lock (Module::GetAllocationModuleCollectionMutex());
+ num_modules = Module::GetNumberAllocatedModules();
+ }
+ else
+ {
+ module_list_ptr = &target->GetImages();
+ }
+ }
+ else
+ {
+ for (size_t i=0; i<argc; ++i)
+ {
+ // Dump specified images (by basename or fullpath)
+ const char *arg_cstr = command.GetArgumentAtIndex(i);
+ const size_t num_matches = FindModulesByName (target, arg_cstr, module_list, use_global_module_list);
+ if (num_matches == 0)
+ {
+ if (argc == 1)
+ {
+ result.AppendErrorWithFormat ("no modules found that match '%s'", arg_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+
+ module_list_ptr = &module_list;
+ }
+
+ if (module_list_ptr != NULL)
+ {
+ locker.Lock(module_list_ptr->GetMutex());
+ num_modules = module_list_ptr->GetSize();
+ }
+
+ if (num_modules > 0)
+ {
+ for (uint32_t image_idx = 0; image_idx<num_modules; ++image_idx)
+ {
+ ModuleSP module_sp;
+ Module *module;
+ if (module_list_ptr)
+ {
+ module_sp = module_list_ptr->GetModuleAtIndexUnlocked(image_idx);
+ module = module_sp.get();
+ }
+ else
+ {
+ module = Module::GetAllocatedModuleAtIndex(image_idx);
+ module_sp = module->shared_from_this();
+ }
+
+ const size_t indent = strm.Printf("[%3u] ", image_idx);
+ PrintModule (target, module, indent, strm);
+
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ if (argc)
+ {
+ if (use_global_module_list)
+ result.AppendError ("the global module list has no matching modules");
+ else
+ result.AppendError ("the target has no matching modules");
+ }
+ else
+ {
+ if (use_global_module_list)
+ result.AppendError ("the global module list is empty");
+ else
+ result.AppendError ("the target has no associated executable images");
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ return result.Succeeded();
+ }
+
+ void
+ PrintModule (Target *target, Module *module, int indent, Stream &strm)
+ {
+
+ if (module == NULL)
+ {
+ strm.PutCString("Null module");
+ return;
+ }
+
+ bool dump_object_name = false;
+ if (m_options.m_format_array.empty())
+ {
+ m_options.m_format_array.push_back(std::make_pair('u', 0));
+ m_options.m_format_array.push_back(std::make_pair('h', 0));
+ m_options.m_format_array.push_back(std::make_pair('f', 0));
+ m_options.m_format_array.push_back(std::make_pair('S', 0));
+ }
+ const size_t num_entries = m_options.m_format_array.size();
+ bool print_space = false;
+ for (size_t i=0; i<num_entries; ++i)
+ {
+ if (print_space)
+ strm.PutChar(' ');
+ print_space = true;
+ const char format_char = m_options.m_format_array[i].first;
+ uint32_t width = m_options.m_format_array[i].second;
+ switch (format_char)
+ {
+ case 'A':
+ DumpModuleArchitecture (strm, module, false, width);
+ break;
+
+ case 't':
+ DumpModuleArchitecture (strm, module, true, width);
+ break;
+
+ case 'f':
+ DumpFullpath (strm, &module->GetFileSpec(), width);
+ dump_object_name = true;
+ break;
+
+ case 'd':
+ DumpDirectory (strm, &module->GetFileSpec(), width);
+ break;
+
+ case 'b':
+ DumpBasename (strm, &module->GetFileSpec(), width);
+ dump_object_name = true;
+ break;
+
+ case 'h':
+ case 'o':
+ // Image header address
+ {
+ uint32_t addr_nibble_width = target ? (target->GetArchitecture().GetAddressByteSize() * 2) : 16;
+
+ ObjectFile *objfile = module->GetObjectFile ();
+ if (objfile)
+ {
+ Address header_addr(objfile->GetHeaderAddress());
+ if (header_addr.IsValid())
+ {
+ if (target && !target->GetSectionLoadList().IsEmpty())
+ {
+ lldb::addr_t header_load_addr = header_addr.GetLoadAddress (target);
+ if (header_load_addr == LLDB_INVALID_ADDRESS)
+ {
+ header_addr.Dump (&strm, target, Address::DumpStyleModuleWithFileAddress, Address::DumpStyleFileAddress);
+ }
+ else
+ {
+ if (format_char == 'o')
+ {
+ // Show the offset of slide for the image
+ strm.Printf ("0x%*.*" PRIx64, addr_nibble_width, addr_nibble_width, header_load_addr - header_addr.GetFileAddress());
+ }
+ else
+ {
+ // Show the load address of the image
+ strm.Printf ("0x%*.*" PRIx64, addr_nibble_width, addr_nibble_width, header_load_addr);
+ }
+ }
+ break;
+ }
+ // The address was valid, but the image isn't loaded, output the address in an appropriate format
+ header_addr.Dump (&strm, target, Address::DumpStyleFileAddress);
+ break;
+ }
+ }
+ strm.Printf ("%*s", addr_nibble_width + 2, "");
+ }
+ break;
+ case 'r':
+ {
+ size_t ref_count = 0;
+ ModuleSP module_sp (module->shared_from_this());
+ if (module_sp)
+ {
+ // Take one away to make sure we don't count our local "module_sp"
+ ref_count = module_sp.use_count() - 1;
+ }
+ if (width)
+ strm.Printf("{%*zu}", width, ref_count);
+ else
+ strm.Printf("{%zu}", ref_count);
+ }
+ break;
+
+ case 's':
+ case 'S':
+ {
+ SymbolVendor *symbol_vendor = module->GetSymbolVendor();
+ if (symbol_vendor)
+ {
+ SymbolFile *symbol_file = symbol_vendor->GetSymbolFile();
+ if (symbol_file)
+ {
+ if (format_char == 'S')
+ {
+ FileSpec &symfile_spec = symbol_file->GetObjectFile()->GetFileSpec();
+ // Dump symbol file only if different from module file
+ if (!symfile_spec || symfile_spec == module->GetFileSpec())
+ {
+ print_space = false;
+ break;
+ }
+ // Add a newline and indent past the index
+ strm.Printf ("\n%*s", indent, "");
+ }
+ DumpFullpath (strm, &symbol_file->GetObjectFile()->GetFileSpec(), width);
+ dump_object_name = true;
+ break;
+ }
+ }
+ strm.Printf("%.*s", width, "<NONE>");
+ }
+ break;
+
+ case 'm':
+ module->GetModificationTime().Dump(&strm, width);
+ break;
+
+ case 'p':
+ strm.Printf("%p", module);
+ break;
+
+ case 'u':
+ DumpModuleUUID(strm, module);
+ break;
+
+ default:
+ break;
+ }
+
+ }
+ if (dump_object_name)
+ {
+ const char *object_name = module->GetObjectName().GetCString();
+ if (object_name)
+ strm.Printf ("(%s)", object_name);
+ }
+ strm.EOL();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectTargetModulesList::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "address", 'a', required_argument, NULL, 0, eArgTypeAddressOrExpression, "Display the image at this address."},
+ { LLDB_OPT_SET_1, false, "arch", 'A', optional_argument, NULL, 0, eArgTypeWidth, "Display the architecture when listing images."},
+ { LLDB_OPT_SET_1, false, "triple", 't', optional_argument, NULL, 0, eArgTypeWidth, "Display the triple when listing images."},
+ { LLDB_OPT_SET_1, false, "header", 'h', no_argument, NULL, 0, eArgTypeNone, "Display the image header address as a load address if debugging, a file address otherwise."},
+ { LLDB_OPT_SET_1, false, "offset", 'o', no_argument, NULL, 0, eArgTypeNone, "Display the image header address offset from the header file address (the slide amount)."},
+ { LLDB_OPT_SET_1, false, "uuid", 'u', no_argument, NULL, 0, eArgTypeNone, "Display the UUID when listing images."},
+ { LLDB_OPT_SET_1, false, "fullpath", 'f', optional_argument, NULL, 0, eArgTypeWidth, "Display the fullpath to the image object file."},
+ { LLDB_OPT_SET_1, false, "directory", 'd', optional_argument, NULL, 0, eArgTypeWidth, "Display the directory with optional width for the image object file."},
+ { LLDB_OPT_SET_1, false, "basename", 'b', optional_argument, NULL, 0, eArgTypeWidth, "Display the basename with optional width for the image object file."},
+ { LLDB_OPT_SET_1, false, "symfile", 's', optional_argument, NULL, 0, eArgTypeWidth, "Display the fullpath to the image symbol file with optional width."},
+ { LLDB_OPT_SET_1, false, "symfile-unique", 'S', optional_argument, NULL, 0, eArgTypeWidth, "Display the symbol file with optional width only if it is different from the executable object file."},
+ { LLDB_OPT_SET_1, false, "mod-time", 'm', optional_argument, NULL, 0, eArgTypeWidth, "Display the modification time with optional width of the module."},
+ { LLDB_OPT_SET_1, false, "ref-count", 'r', optional_argument, NULL, 0, eArgTypeWidth, "Display the reference count if the module is still in the shared module cache."},
+ { LLDB_OPT_SET_1, false, "pointer", 'p', optional_argument, NULL, 0, eArgTypeNone, "Display the module pointer."},
+ { LLDB_OPT_SET_1, false, "global", 'g', no_argument, NULL, 0, eArgTypeNone, "Display the modules from the global module list, not just the current target."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#pragma mark CommandObjectTargetModulesShowUnwind
+
+//----------------------------------------------------------------------
+// Lookup unwind information in images
+//----------------------------------------------------------------------
+
+class CommandObjectTargetModulesShowUnwind : public CommandObjectParsed
+{
+public:
+
+ enum
+ {
+ eLookupTypeInvalid = -1,
+ eLookupTypeAddress = 0,
+ eLookupTypeSymbol,
+ eLookupTypeFunction,
+ eLookupTypeFunctionOrSymbol,
+ kNumLookupTypes
+ };
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter),
+ m_type(eLookupTypeInvalid),
+ m_str(),
+ m_addr(LLDB_INVALID_ADDRESS)
+ {
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ {
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ m_type = eLookupTypeAddress;
+ m_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ if (m_addr == LLDB_INVALID_ADDRESS)
+ error.SetErrorStringWithFormat ("invalid address string '%s'", option_arg);
+ break;
+ }
+
+ case 'n':
+ {
+ m_str = option_arg;
+ m_type = eLookupTypeFunctionOrSymbol;
+ break;
+ }
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_type = eLookupTypeInvalid;
+ m_str.clear();
+ m_addr = LLDB_INVALID_ADDRESS;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ int m_type; // Should be a eLookupTypeXXX enum after parsing options
+ std::string m_str; // Holds name lookup
+ lldb::addr_t m_addr; // Holds the address to lookup
+ };
+
+ CommandObjectTargetModulesShowUnwind (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules show-unwind",
+ "Show synthesized unwind instructions for a function.",
+ NULL,
+ eFlagRequiresTarget |
+ eFlagRequiresProcess |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetModulesShowUnwind ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ Process *process = m_exe_ctx.GetProcessPtr();
+ ABI *abi = NULL;
+ if (process)
+ abi = process->GetABI().get();
+
+ if (process == NULL)
+ {
+ result.AppendError ("You must have a process running to use this command.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ThreadList threads(process->GetThreadList());
+ if (threads.GetSize() == 0)
+ {
+ result.AppendError ("The process must be paused to use this command.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ThreadSP thread(threads.GetThreadAtIndex(0));
+ if (thread.get() == NULL)
+ {
+ result.AppendError ("The process must be paused to use this command.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ SymbolContextList sc_list;
+
+ if (m_options.m_type == eLookupTypeFunctionOrSymbol)
+ {
+ ConstString function_name (m_options.m_str.c_str());
+ target->GetImages().FindFunctions (function_name, eFunctionNameTypeAuto, true, false, true, sc_list);
+ }
+ else if (m_options.m_type == eLookupTypeAddress && target)
+ {
+ Address addr;
+ if (target->GetSectionLoadList().ResolveLoadAddress (m_options.m_addr, addr))
+ {
+ SymbolContext sc;
+ ModuleSP module_sp (addr.GetModule());
+ module_sp->ResolveSymbolContextForAddress (addr, eSymbolContextEverything, sc);
+ if (sc.function || sc.symbol)
+ {
+ sc_list.Append(sc);
+ }
+ }
+ }
+
+ size_t num_matches = sc_list.GetSize();
+ for (uint32_t idx = 0; idx < num_matches; idx++)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(idx, sc);
+ if (sc.symbol == NULL && sc.function == NULL)
+ continue;
+ if (sc.module_sp.get() == NULL || sc.module_sp->GetObjectFile() == NULL)
+ continue;
+ AddressRange range;
+ if (!sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range))
+ continue;
+ if (!range.GetBaseAddress().IsValid())
+ continue;
+ ConstString funcname(sc.GetFunctionName());
+ if (funcname.IsEmpty())
+ continue;
+ addr_t start_addr = range.GetBaseAddress().GetLoadAddress(target);
+ if (abi)
+ start_addr = abi->FixCodeAddress(start_addr);
+
+ FuncUnwindersSP func_unwinders_sp (sc.module_sp->GetObjectFile()->GetUnwindTable().GetUncachedFuncUnwindersContainingAddress(start_addr, sc));
+ if (func_unwinders_sp.get() == NULL)
+ continue;
+
+ Address first_non_prologue_insn (func_unwinders_sp->GetFirstNonPrologueInsn(*target));
+ if (first_non_prologue_insn.IsValid())
+ {
+ result.GetOutputStream().Printf("First non-prologue instruction is at address 0x%" PRIx64 " or offset %" PRId64 " into the function.\n", first_non_prologue_insn.GetLoadAddress(target), first_non_prologue_insn.GetLoadAddress(target) - start_addr);
+ result.GetOutputStream().Printf ("\n");
+ }
+
+ UnwindPlanSP non_callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtNonCallSite(*thread.get());
+ if (non_callsite_unwind_plan.get())
+ {
+ result.GetOutputStream().Printf("Asynchronous (not restricted to call-sites) UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
+ non_callsite_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf ("\n");
+ }
+
+ UnwindPlanSP callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite(-1);
+ if (callsite_unwind_plan.get())
+ {
+ result.GetOutputStream().Printf("Synchronous (restricted to call-sites) UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
+ callsite_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf ("\n");
+ }
+
+ UnwindPlanSP arch_default_unwind_plan = func_unwinders_sp->GetUnwindPlanArchitectureDefault(*thread.get());
+ if (arch_default_unwind_plan.get())
+ {
+ result.GetOutputStream().Printf("Architecture default UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
+ arch_default_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf ("\n");
+ }
+
+ UnwindPlanSP fast_unwind_plan = func_unwinders_sp->GetUnwindPlanFastUnwind(*thread.get());
+ if (fast_unwind_plan.get())
+ {
+ result.GetOutputStream().Printf("Fast UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
+ fast_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf ("\n");
+ }
+
+
+ result.GetOutputStream().Printf ("\n");
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectTargetModulesShowUnwind::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "name", 'n', required_argument, NULL, 0, eArgTypeFunctionName, "Show unwind instructions for a function or symbol name."},
+ { LLDB_OPT_SET_2, false, "address", 'a', required_argument, NULL, 0, eArgTypeAddressOrExpression, "Show unwind instructions for a function or symbol containing an address"},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//----------------------------------------------------------------------
+// Lookup information in images
+//----------------------------------------------------------------------
+class CommandObjectTargetModulesLookup : public CommandObjectParsed
+{
+public:
+
+ enum
+ {
+ eLookupTypeInvalid = -1,
+ eLookupTypeAddress = 0,
+ eLookupTypeSymbol,
+ eLookupTypeFileLine, // Line is optional
+ eLookupTypeFunction,
+ eLookupTypeFunctionOrSymbol,
+ eLookupTypeType,
+ kNumLookupTypes
+ };
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ OptionParsingStarting();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ {
+ m_type = eLookupTypeAddress;
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ m_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ }
+ break;
+
+ case 'o':
+ m_offset = Args::StringToUInt64(option_arg, LLDB_INVALID_ADDRESS);
+ if (m_offset == LLDB_INVALID_ADDRESS)
+ error.SetErrorStringWithFormat ("invalid offset string '%s'", option_arg);
+ break;
+
+ case 's':
+ m_str = option_arg;
+ m_type = eLookupTypeSymbol;
+ break;
+
+ case 'f':
+ m_file.SetFile (option_arg, false);
+ m_type = eLookupTypeFileLine;
+ break;
+
+ case 'i':
+ m_include_inlines = false;
+ break;
+
+ case 'l':
+ m_line_number = Args::StringToUInt32(option_arg, UINT32_MAX);
+ if (m_line_number == UINT32_MAX)
+ error.SetErrorStringWithFormat ("invalid line number string '%s'", option_arg);
+ else if (m_line_number == 0)
+ error.SetErrorString ("zero is an invalid line number");
+ m_type = eLookupTypeFileLine;
+ break;
+
+ case 'F':
+ m_str = option_arg;
+ m_type = eLookupTypeFunction;
+ break;
+
+ case 'n':
+ m_str = option_arg;
+ m_type = eLookupTypeFunctionOrSymbol;
+ break;
+
+ case 't':
+ m_str = option_arg;
+ m_type = eLookupTypeType;
+ break;
+
+ case 'v':
+ m_verbose = 1;
+ break;
+
+ case 'A':
+ m_print_all = true;
+ break;
+
+ case 'r':
+ m_use_regex = true;
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_type = eLookupTypeInvalid;
+ m_str.clear();
+ m_file.Clear();
+ m_addr = LLDB_INVALID_ADDRESS;
+ m_offset = 0;
+ m_line_number = 0;
+ m_use_regex = false;
+ m_include_inlines = true;
+ m_verbose = false;
+ m_print_all = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+ int m_type; // Should be a eLookupTypeXXX enum after parsing options
+ std::string m_str; // Holds name lookup
+ FileSpec m_file; // Files for file lookups
+ lldb::addr_t m_addr; // Holds the address to lookup
+ lldb::addr_t m_offset; // Subtract this offset from m_addr before doing lookups.
+ uint32_t m_line_number; // Line number for file+line lookups
+ bool m_use_regex; // Name lookups in m_str are regular expressions.
+ bool m_include_inlines;// Check for inline entries when looking up by file/line.
+ bool m_verbose; // Enable verbose lookup info
+ bool m_print_all; // Print all matches, even in cases where there's a best match.
+
+ };
+
+ CommandObjectTargetModulesLookup (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules lookup",
+ "Look up information within executable and dependent shared library images.",
+ NULL,
+ eFlagRequiresTarget),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData file_arg;
+
+ // Define the first (and only) variant of this arg.
+ file_arg.arg_type = eArgTypeFilename;
+ file_arg.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (file_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectTargetModulesLookup ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ bool
+ LookupHere (CommandInterpreter &interpreter, CommandReturnObject &result, bool &syntax_error)
+ {
+ switch (m_options.m_type)
+ {
+ case eLookupTypeAddress:
+ case eLookupTypeFileLine:
+ case eLookupTypeFunction:
+ case eLookupTypeFunctionOrSymbol:
+ case eLookupTypeSymbol:
+ default:
+ return false;
+ case eLookupTypeType:
+ break;
+ }
+
+ StackFrameSP frame = m_exe_ctx.GetFrameSP();
+
+ if (!frame)
+ return false;
+
+ const SymbolContext &sym_ctx(frame->GetSymbolContext(eSymbolContextModule));
+
+ if (!sym_ctx.module_sp)
+ return false;
+
+ switch (m_options.m_type)
+ {
+ default:
+ return false;
+ case eLookupTypeType:
+ if (!m_options.m_str.empty())
+ {
+ if (LookupTypeHere (m_interpreter,
+ result.GetOutputStream(),
+ sym_ctx,
+ m_options.m_str.c_str(),
+ m_options.m_use_regex))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ break;
+ }
+
+ return true;
+ }
+
+ bool
+ LookupInModule (CommandInterpreter &interpreter, Module *module, CommandReturnObject &result, bool &syntax_error)
+ {
+ switch (m_options.m_type)
+ {
+ case eLookupTypeAddress:
+ if (m_options.m_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (LookupAddressInModule (m_interpreter,
+ result.GetOutputStream(),
+ module,
+ eSymbolContextEverything,
+ m_options.m_addr,
+ m_options.m_offset,
+ m_options.m_verbose))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ break;
+
+ case eLookupTypeSymbol:
+ if (!m_options.m_str.empty())
+ {
+ if (LookupSymbolInModule (m_interpreter,
+ result.GetOutputStream(),
+ module,
+ m_options.m_str.c_str(),
+ m_options.m_use_regex,
+ m_options.m_verbose))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ break;
+
+ case eLookupTypeFileLine:
+ if (m_options.m_file)
+ {
+
+ if (LookupFileAndLineInModule (m_interpreter,
+ result.GetOutputStream(),
+ module,
+ m_options.m_file,
+ m_options.m_line_number,
+ m_options.m_include_inlines,
+ m_options.m_verbose))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ break;
+
+ case eLookupTypeFunctionOrSymbol:
+ case eLookupTypeFunction:
+ if (!m_options.m_str.empty())
+ {
+ if (LookupFunctionInModule (m_interpreter,
+ result.GetOutputStream(),
+ module,
+ m_options.m_str.c_str(),
+ m_options.m_use_regex,
+ m_options.m_include_inlines,
+ m_options.m_type == eLookupTypeFunctionOrSymbol, // include symbols
+ m_options.m_verbose))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ break;
+
+
+ case eLookupTypeType:
+ if (!m_options.m_str.empty())
+ {
+ if (LookupTypeInModule (m_interpreter,
+ result.GetOutputStream(),
+ module,
+ m_options.m_str.c_str(),
+ m_options.m_use_regex))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ break;
+
+ default:
+ m_options.GenerateOptionUsage (result.GetErrorStream(), this);
+ syntax_error = true;
+ break;
+ }
+
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ bool syntax_error = false;
+ uint32_t i;
+ uint32_t num_successful_lookups = 0;
+ uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
+ result.GetOutputStream().SetAddressByteSize(addr_byte_size);
+ result.GetErrorStream().SetAddressByteSize(addr_byte_size);
+ // Dump all sections for all modules images
+
+ if (command.GetArgumentCount() == 0)
+ {
+ ModuleSP current_module;
+
+ // Where it is possible to look in the current symbol context
+ // first, try that. If this search was successful and --all
+ // was not passed, don't print anything else.
+ if (LookupHere (m_interpreter, result, syntax_error))
+ {
+ result.GetOutputStream().EOL();
+ num_successful_lookups++;
+ if (!m_options.m_print_all)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+ }
+
+ // Dump all sections for all other modules
+
+ const ModuleList &target_modules = target->GetImages();
+ Mutex::Locker modules_locker(target_modules.GetMutex());
+ const size_t num_modules = target_modules.GetSize();
+ if (num_modules > 0)
+ {
+ for (i = 0; i<num_modules && syntax_error == false; ++i)
+ {
+ Module *module_pointer = target_modules.GetModulePointerAtIndexUnlocked(i);
+
+ if (module_pointer != current_module.get() &&
+ LookupInModule (m_interpreter, target_modules.GetModulePointerAtIndexUnlocked(i), result, syntax_error))
+ {
+ result.GetOutputStream().EOL();
+ num_successful_lookups++;
+ }
+ }
+ }
+ else
+ {
+ result.AppendError ("the target has no associated executable images");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ // Dump specified images (by basename or fullpath)
+ const char *arg_cstr;
+ for (i = 0; (arg_cstr = command.GetArgumentAtIndex(i)) != NULL && syntax_error == false; ++i)
+ {
+ ModuleList module_list;
+ const size_t num_matches = FindModulesByName (target, arg_cstr, module_list, false);
+ if (num_matches > 0)
+ {
+ for (size_t j=0; j<num_matches; ++j)
+ {
+ Module *module = module_list.GetModulePointerAtIndex(j);
+ if (module)
+ {
+ if (LookupInModule (m_interpreter, module, result, syntax_error))
+ {
+ result.GetOutputStream().EOL();
+ num_successful_lookups++;
+ }
+ }
+ }
+ }
+ else
+ result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr);
+ }
+ }
+
+ if (num_successful_lookups > 0)
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ else
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectTargetModulesLookup::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, true, "address", 'a', required_argument, NULL, 0, eArgTypeAddressOrExpression, "Lookup an address in one or more target modules."},
+ { LLDB_OPT_SET_1, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset, "When looking up an address subtract <offset> from any addresses before doing the lookup."},
+ { LLDB_OPT_SET_2| LLDB_OPT_SET_4 | LLDB_OPT_SET_5
+ /* FIXME: re-enable this for types when the LookupTypeInModule actually uses the regex option: | LLDB_OPT_SET_6 */ ,
+ false, "regex", 'r', no_argument, NULL, 0, eArgTypeNone, "The <name> argument for name lookups are regular expressions."},
+ { LLDB_OPT_SET_2, true, "symbol", 's', required_argument, NULL, 0, eArgTypeSymbol, "Lookup a symbol by name in the symbol tables in one or more target modules."},
+ { LLDB_OPT_SET_3, true, "file", 'f', required_argument, NULL, 0, eArgTypeFilename, "Lookup a file by fullpath or basename in one or more target modules."},
+ { LLDB_OPT_SET_3, false, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum, "Lookup a line number in a file (must be used in conjunction with --file)."},
+ { LLDB_OPT_SET_FROM_TO(3,5),
+ false, "no-inlines", 'i', no_argument, NULL, 0, eArgTypeNone, "Ignore inline entries (must be used in conjunction with --file or --function)."},
+ { LLDB_OPT_SET_4, true, "function", 'F', required_argument, NULL, 0, eArgTypeFunctionName, "Lookup a function by name in the debug symbols in one or more target modules."},
+ { LLDB_OPT_SET_5, true, "name", 'n', required_argument, NULL, 0, eArgTypeFunctionOrSymbol, "Lookup a function or symbol by name in one or more target modules."},
+ { LLDB_OPT_SET_6, true, "type", 't', required_argument, NULL, 0, eArgTypeName, "Lookup a type by name in the debug symbols in one or more target modules."},
+ { LLDB_OPT_SET_ALL, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone, "Enable verbose lookup information."},
+ { LLDB_OPT_SET_ALL, false, "all", 'A', no_argument, NULL, 0, eArgTypeNone, "Print all matches, not just the best match, if a best match is available."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+#pragma mark CommandObjectMultiwordImageSearchPaths
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordImageSearchPaths
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetModulesImageSearchPaths : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectTargetModulesImageSearchPaths (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "target modules search-paths",
+ "A set of commands for operating on debugger target image search paths.",
+ "target modules search-paths <subcommand> [<subcommand-options>]")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTargetModulesSearchPathsAdd (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTargetModulesSearchPathsClear (interpreter)));
+ LoadSubCommand ("insert", CommandObjectSP (new CommandObjectTargetModulesSearchPathsInsert (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTargetModulesSearchPathsList (interpreter)));
+ LoadSubCommand ("query", CommandObjectSP (new CommandObjectTargetModulesSearchPathsQuery (interpreter)));
+ }
+
+ ~CommandObjectTargetModulesImageSearchPaths()
+ {
+ }
+};
+
+
+
+#pragma mark CommandObjectTargetModules
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetModules
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetModules : public CommandObjectMultiword
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectTargetModules(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "target modules",
+ "A set of commands for accessing information for one or more target modules.",
+ "target modules <sub-command> ...")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTargetModulesAdd (interpreter)));
+ LoadSubCommand ("load", CommandObjectSP (new CommandObjectTargetModulesLoad (interpreter)));
+ LoadSubCommand ("dump", CommandObjectSP (new CommandObjectTargetModulesDump (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTargetModulesList (interpreter)));
+ LoadSubCommand ("lookup", CommandObjectSP (new CommandObjectTargetModulesLookup (interpreter)));
+ LoadSubCommand ("search-paths", CommandObjectSP (new CommandObjectTargetModulesImageSearchPaths (interpreter)));
+ LoadSubCommand ("show-unwind", CommandObjectSP (new CommandObjectTargetModulesShowUnwind (interpreter)));
+
+ }
+ virtual
+ ~CommandObjectTargetModules()
+ {
+ }
+
+private:
+ //------------------------------------------------------------------
+ // For CommandObjectTargetModules only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectTargetModules);
+};
+
+
+
+class CommandObjectTargetSymbolsAdd : public CommandObjectParsed
+{
+public:
+ CommandObjectTargetSymbolsAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target symbols add",
+ "Add a debug symbol file to one of the target's current modules by specifying a path to a debug symbols file, or using the options to specify a module to download symbols for.",
+ "target symbols add [<symfile>]", eFlagRequiresTarget),
+ m_option_group (interpreter),
+ m_file_option (LLDB_OPT_SET_1, false, "shlib", 's', CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Fullpath or basename for module to find debug symbols for."),
+ m_current_frame_option (LLDB_OPT_SET_2, false, "frame", 'F', "Locate the debug symbols the currently selected frame.", false, true)
+
+ {
+ m_option_group.Append (&m_uuid_option_group, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_file_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_current_frame_option, LLDB_OPT_SET_2, LLDB_OPT_SET_2);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectTargetSymbolsAdd ()
+ {
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eDiskFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+
+protected:
+
+ bool
+ AddModuleSymbols (Target *target,
+ ModuleSpec &module_spec,
+ bool &flush,
+ CommandReturnObject &result)
+ {
+ const FileSpec &symbol_fspec = module_spec.GetSymbolFileSpec();
+ if (symbol_fspec)
+ {
+ char symfile_path[PATH_MAX];
+ symbol_fspec.GetPath (symfile_path, sizeof(symfile_path));
+
+ if (!module_spec.GetUUID().IsValid())
+ {
+ if (!module_spec.GetFileSpec() && !module_spec.GetPlatformFileSpec())
+ module_spec.GetFileSpec().GetFilename() = symbol_fspec.GetFilename();
+ }
+ // We now have a module that represents a symbol file
+ // that can be used for a module that might exist in the
+ // current target, so we need to find that module in the
+ // target
+ ModuleList matching_module_list;
+
+ size_t num_matches = 0;
+ // First extract all module specs from the symbol file
+ lldb_private::ModuleSpecList symfile_module_specs;
+ if (ObjectFile::GetModuleSpecifications(module_spec.GetSymbolFileSpec(), 0, 0, symfile_module_specs))
+ {
+ // Now extract the module spec that matches the target architecture
+ ModuleSpec target_arch_module_spec;
+ ModuleSpec symfile_module_spec;
+ target_arch_module_spec.GetArchitecture() = target->GetArchitecture();
+ if (symfile_module_specs.FindMatchingModuleSpec(target_arch_module_spec, symfile_module_spec))
+ {
+ // See if it has a UUID?
+ if (symfile_module_spec.GetUUID().IsValid())
+ {
+ // It has a UUID, look for this UUID in the target modules
+ ModuleSpec symfile_uuid_module_spec;
+ symfile_uuid_module_spec.GetUUID() = symfile_module_spec.GetUUID();
+ num_matches = target->GetImages().FindModules (symfile_uuid_module_spec, matching_module_list);
+ }
+ }
+
+ if (num_matches == 0)
+ {
+ // No matches yet, iterate through the module specs to find a UUID value that
+ // we can match up to an image in our target
+ const size_t num_symfile_module_specs = symfile_module_specs.GetSize();
+ for (size_t i=0; i<num_symfile_module_specs && num_matches == 0; ++i)
+ {
+ if (symfile_module_specs.GetModuleSpecAtIndex(i, symfile_module_spec))
+ {
+ if (symfile_module_spec.GetUUID().IsValid())
+ {
+ // It has a UUID, look for this UUID in the target modules
+ ModuleSpec symfile_uuid_module_spec;
+ symfile_uuid_module_spec.GetUUID() = symfile_module_spec.GetUUID();
+ num_matches = target->GetImages().FindModules (symfile_uuid_module_spec, matching_module_list);
+ }
+ }
+ }
+ }
+ }
+
+ // Just try to match up the file by basename if we have no matches at this point
+ if (num_matches == 0)
+ num_matches = target->GetImages().FindModules (module_spec, matching_module_list);
+
+ while (num_matches == 0)
+ {
+ ConstString filename_no_extension(module_spec.GetFileSpec().GetFileNameStrippingExtension());
+ // Empty string returned, lets bail
+ if (!filename_no_extension)
+ break;
+
+ // Check if there was no extension to strip and the basename is the same
+ if (filename_no_extension == module_spec.GetFileSpec().GetFilename())
+ break;
+
+ // Replace basename with one less extension
+ module_spec.GetFileSpec().GetFilename() = filename_no_extension;
+
+ num_matches = target->GetImages().FindModules (module_spec, matching_module_list);
+
+ }
+
+ if (num_matches > 1)
+ {
+ result.AppendErrorWithFormat ("multiple modules match symbol file '%s', use the --uuid option to resolve the ambiguity.\n", symfile_path);
+ }
+ else if (num_matches == 1)
+ {
+ ModuleSP module_sp (matching_module_list.GetModuleAtIndex(0));
+
+ // The module has not yet created its symbol vendor, we can just
+ // give the existing target module the symfile path to use for
+ // when it decides to create it!
+ module_sp->SetSymbolFileFileSpec (symbol_fspec);
+
+ SymbolVendor *symbol_vendor = module_sp->GetSymbolVendor(true, &result.GetErrorStream());
+ if (symbol_vendor)
+ {
+ SymbolFile *symbol_file = symbol_vendor->GetSymbolFile();
+
+ if (symbol_file)
+ {
+ ObjectFile *object_file = symbol_file->GetObjectFile();
+
+ if (object_file && object_file->GetFileSpec() == symbol_fspec)
+ {
+ // Provide feedback that the symfile has been successfully added.
+ const FileSpec &module_fs = module_sp->GetFileSpec();
+ result.AppendMessageWithFormat("symbol file '%s' has been added to '%s'\n",
+ symfile_path,
+ module_fs.GetPath().c_str());
+
+ // Let clients know something changed in the module
+ // if it is currently loaded
+ ModuleList module_list;
+ module_list.Append (module_sp);
+ target->SymbolsDidLoad (module_list);
+
+ // Make sure we load any scripting resources that may be embedded
+ // in the debug info files in case the platform supports that.
+ Error error;
+ StreamString feedback_stream;
+ module_sp->LoadScriptingResourceInTarget (target, error,&feedback_stream);
+ if (error.Fail() && error.AsCString())
+ result.AppendWarningWithFormat("unable to load scripting data for module %s - error reported was %s",
+ module_sp->GetFileSpec().GetFileNameStrippingExtension().GetCString(),
+ error.AsCString());
+ else if (feedback_stream.GetSize())
+ result.AppendWarningWithFormat("%s",feedback_stream.GetData());
+
+ flush = true;
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ }
+ // Clear the symbol file spec if anything went wrong
+ module_sp->SetSymbolFileFileSpec (FileSpec());
+ }
+
+ if (module_spec.GetUUID().IsValid())
+ {
+ StreamString ss_symfile_uuid;
+ module_spec.GetUUID().Dump(&ss_symfile_uuid);
+ result.AppendErrorWithFormat ("symbol file '%s' (%s) does not match any existing module%s\n",
+ symfile_path,
+ ss_symfile_uuid.GetData(),
+ (symbol_fspec.GetFileType() != FileSpec::eFileTypeRegular)
+ ? "\n please specify the full path to the symbol file"
+ : "");
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("symbol file '%s' does not match any existing module%s\n",
+ symfile_path,
+ (symbol_fspec.GetFileType() != FileSpec::eFileTypeRegular)
+ ? "\n please specify the full path to the symbol file"
+ : "");
+ }
+ }
+ else
+ {
+ result.AppendError ("one or more executable image paths must be specified");
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result)
+ {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ result.SetStatus (eReturnStatusFailed);
+ bool flush = false;
+ ModuleSpec module_spec;
+ const bool uuid_option_set = m_uuid_option_group.GetOptionValue().OptionWasSet();
+ const bool file_option_set = m_file_option.GetOptionValue().OptionWasSet();
+ const bool frame_option_set = m_current_frame_option.GetOptionValue().OptionWasSet();
+
+ const size_t argc = args.GetArgumentCount();
+ if (argc == 0)
+ {
+ if (uuid_option_set || file_option_set || frame_option_set)
+ {
+ bool success = false;
+ bool error_set = false;
+ if (frame_option_set)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ const StateType process_state = process->GetState();
+ if (StateIsStoppedState (process_state, true))
+ {
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ ModuleSP frame_module_sp (frame->GetSymbolContext(eSymbolContextModule).module_sp);
+ if (frame_module_sp)
+ {
+ if (frame_module_sp->GetPlatformFileSpec().Exists())
+ {
+ module_spec.GetArchitecture() = frame_module_sp->GetArchitecture();
+ module_spec.GetFileSpec() = frame_module_sp->GetPlatformFileSpec();
+ }
+ module_spec.GetUUID() = frame_module_sp->GetUUID();
+ success = module_spec.GetUUID().IsValid() || module_spec.GetFileSpec();
+ }
+ else
+ {
+ result.AppendError ("frame has no module");
+ error_set = true;
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid current frame");
+ error_set = true;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("process is not stopped: %s", StateAsCString(process_state));
+ error_set = true;
+ }
+ }
+ else
+ {
+ result.AppendError ("a process must exist in order to use the --frame option");
+ error_set = true;
+ }
+ }
+ else
+ {
+ if (uuid_option_set)
+ {
+ module_spec.GetUUID() = m_uuid_option_group.GetOptionValue().GetCurrentValue();
+ success |= module_spec.GetUUID().IsValid();
+ }
+ else if (file_option_set)
+ {
+ module_spec.GetFileSpec() = m_file_option.GetOptionValue().GetCurrentValue();
+ ModuleSP module_sp (target->GetImages().FindFirstModule(module_spec));
+ if (module_sp)
+ {
+ module_spec.GetFileSpec() = module_sp->GetFileSpec();
+ module_spec.GetPlatformFileSpec() = module_sp->GetPlatformFileSpec();
+ module_spec.GetUUID() = module_sp->GetUUID();
+ module_spec.GetArchitecture() = module_sp->GetArchitecture();
+ }
+ else
+ {
+ module_spec.GetArchitecture() = target->GetArchitecture();
+ }
+ success |= module_spec.GetFileSpec().Exists();
+ }
+ }
+
+ if (success)
+ {
+ if (Symbols::DownloadObjectAndSymbolFile (module_spec))
+ {
+ if (module_spec.GetSymbolFileSpec())
+ success = AddModuleSymbols (target, module_spec, flush, result);
+ }
+ }
+
+ if (!success && !error_set)
+ {
+ StreamString error_strm;
+ if (uuid_option_set)
+ {
+ error_strm.PutCString("unable to find debug symbols for UUID ");
+ module_spec.GetUUID().Dump (&error_strm);
+ }
+ else if (file_option_set)
+ {
+ error_strm.PutCString("unable to find debug symbols for the executable file ");
+ error_strm << module_spec.GetFileSpec();
+ }
+ else if (frame_option_set)
+ {
+ error_strm.PutCString("unable to find debug symbols for the current frame");
+ }
+ result.AppendError (error_strm.GetData());
+ }
+ }
+ else
+ {
+ result.AppendError ("one or more symbol file paths must be specified, or options must be specified");
+ }
+ }
+ else
+ {
+ if (uuid_option_set)
+ {
+ result.AppendError ("specify either one or more paths to symbol files or use the --uuid option without arguments");
+ }
+ else if (file_option_set)
+ {
+ result.AppendError ("specify either one or more paths to symbol files or use the --file option without arguments");
+ }
+ else if (frame_option_set)
+ {
+ result.AppendError ("specify either one or more paths to symbol files or use the --frame option without arguments");
+ }
+ else
+ {
+ PlatformSP platform_sp (target->GetPlatform());
+
+ for (size_t i=0; i<argc; ++i)
+ {
+ const char *symfile_path = args.GetArgumentAtIndex(i);
+ if (symfile_path)
+ {
+ module_spec.GetSymbolFileSpec().SetFile(symfile_path, true);
+ if (platform_sp)
+ {
+ FileSpec symfile_spec;
+ if (platform_sp->ResolveSymbolFile(*target, module_spec, symfile_spec).Success())
+ module_spec.GetSymbolFileSpec() = symfile_spec;
+ }
+
+ ArchSpec arch;
+ bool symfile_exists = module_spec.GetSymbolFileSpec().Exists();
+
+ if (symfile_exists)
+ {
+ if (!AddModuleSymbols (target, module_spec, flush, result))
+ break;
+ }
+ else
+ {
+ char resolved_symfile_path[PATH_MAX];
+ if (module_spec.GetSymbolFileSpec().GetPath (resolved_symfile_path, sizeof(resolved_symfile_path)))
+ {
+ if (strcmp (resolved_symfile_path, symfile_path) != 0)
+ {
+ result.AppendErrorWithFormat ("invalid module path '%s' with resolved path '%s'\n", symfile_path, resolved_symfile_path);
+ break;
+ }
+ }
+ result.AppendErrorWithFormat ("invalid module path '%s'\n", symfile_path);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (flush)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process)
+ process->Flush();
+ }
+ return result.Succeeded();
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupUUID m_uuid_option_group;
+ OptionGroupFile m_file_option;
+ OptionGroupBoolean m_current_frame_option;
+
+
+};
+
+
+#pragma mark CommandObjectTargetSymbols
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetSymbols
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetSymbols : public CommandObjectMultiword
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectTargetSymbols(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "target symbols",
+ "A set of commands for adding and managing debug symbol files.",
+ "target symbols <sub-command> ...")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTargetSymbolsAdd (interpreter)));
+
+ }
+ virtual
+ ~CommandObjectTargetSymbols()
+ {
+ }
+
+private:
+ //------------------------------------------------------------------
+ // For CommandObjectTargetModules only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectTargetSymbols);
+};
+
+
+#pragma mark CommandObjectTargetStopHookAdd
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetStopHookAdd
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetStopHookAdd : public CommandObjectParsed
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter),
+ m_line_start(0),
+ m_line_end (UINT_MAX),
+ m_func_name_type_mask (eFunctionNameTypeAuto),
+ m_sym_ctx_specified (false),
+ m_thread_specified (false),
+ m_use_one_liner (false),
+ m_one_liner()
+ {
+ }
+
+ ~CommandOptions () {}
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+ bool success;
+
+ switch (short_option)
+ {
+ case 'c':
+ m_class_name = option_arg;
+ m_sym_ctx_specified = true;
+ break;
+
+ case 'e':
+ m_line_end = Args::StringToUInt32 (option_arg, UINT_MAX, 0, &success);
+ if (!success)
+ {
+ error.SetErrorStringWithFormat ("invalid end line number: \"%s\"", option_arg);
+ break;
+ }
+ m_sym_ctx_specified = true;
+ break;
+
+ case 'l':
+ m_line_start = Args::StringToUInt32 (option_arg, 0, 0, &success);
+ if (!success)
+ {
+ error.SetErrorStringWithFormat ("invalid start line number: \"%s\"", option_arg);
+ break;
+ }
+ m_sym_ctx_specified = true;
+ break;
+
+ case 'i':
+ m_no_inlines = true;
+ break;
+
+ case 'n':
+ m_function_name = option_arg;
+ m_func_name_type_mask |= eFunctionNameTypeAuto;
+ m_sym_ctx_specified = true;
+ break;
+
+ case 'f':
+ m_file_name = option_arg;
+ m_sym_ctx_specified = true;
+ break;
+ case 's':
+ m_module_name = option_arg;
+ m_sym_ctx_specified = true;
+ break;
+ case 't' :
+ {
+ m_thread_id = Args::StringToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0);
+ if (m_thread_id == LLDB_INVALID_THREAD_ID)
+ error.SetErrorStringWithFormat ("invalid thread id string '%s'", option_arg);
+ m_thread_specified = true;
+ }
+ break;
+ case 'T':
+ m_thread_name = option_arg;
+ m_thread_specified = true;
+ break;
+ case 'q':
+ m_queue_name = option_arg;
+ m_thread_specified = true;
+ break;
+ case 'x':
+ {
+ m_thread_index = Args::StringToUInt32(option_arg, UINT32_MAX, 0);
+ if (m_thread_id == UINT32_MAX)
+ error.SetErrorStringWithFormat ("invalid thread index string '%s'", option_arg);
+ m_thread_specified = true;
+ }
+ break;
+ case 'o':
+ m_use_one_liner = true;
+ m_one_liner = option_arg;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option %c.", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_class_name.clear();
+ m_function_name.clear();
+ m_line_start = 0;
+ m_line_end = UINT_MAX;
+ m_file_name.clear();
+ m_module_name.clear();
+ m_func_name_type_mask = eFunctionNameTypeAuto;
+ m_thread_id = LLDB_INVALID_THREAD_ID;
+ m_thread_index = UINT32_MAX;
+ m_thread_name.clear();
+ m_queue_name.clear();
+
+ m_no_inlines = false;
+ m_sym_ctx_specified = false;
+ m_thread_specified = false;
+
+ m_use_one_liner = false;
+ m_one_liner.clear();
+ }
+
+
+ static OptionDefinition g_option_table[];
+
+ std::string m_class_name;
+ std::string m_function_name;
+ uint32_t m_line_start;
+ uint32_t m_line_end;
+ std::string m_file_name;
+ std::string m_module_name;
+ uint32_t m_func_name_type_mask; // A pick from lldb::FunctionNameType.
+ lldb::tid_t m_thread_id;
+ uint32_t m_thread_index;
+ std::string m_thread_name;
+ std::string m_queue_name;
+ bool m_sym_ctx_specified;
+ bool m_no_inlines;
+ bool m_thread_specified;
+ // Instance variables to hold the values for one_liner options.
+ bool m_use_one_liner;
+ std::string m_one_liner;
+ };
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ CommandObjectTargetStopHookAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target stop-hook add ",
+ "Add a hook to be executed when the target stops.",
+ "target stop-hook add"),
+ m_options (interpreter)
+ {
+ }
+
+ ~CommandObjectTargetStopHookAdd ()
+ {
+ }
+
+ static size_t
+ ReadCommandsCallbackFunction (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ Target::StopHook *new_stop_hook = ((Target::StopHook *) baton);
+ static bool got_interrupted;
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ if (!batch_mode)
+ {
+ out_stream->Printf ("%s\n", "Enter your stop hook command(s). Type 'DONE' to end.");
+ if (reader.GetPrompt())
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ got_interrupted = false;
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderReactivate:
+ if (reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ got_interrupted = false;
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderGotToken:
+ if (bytes && bytes_len && baton)
+ {
+ StringList *commands = new_stop_hook->GetCommandPointer();
+ if (commands)
+ {
+ commands->AppendString (bytes, bytes_len);
+ }
+ }
+ if (!reader.IsDone() && reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ break;
+
+ case eInputReaderInterrupt:
+ {
+ // Finish, and cancel the stop hook.
+ new_stop_hook->GetTarget()->RemoveStopHookByID(new_stop_hook->GetID());
+ if (!batch_mode)
+ {
+ out_stream->Printf ("Stop hook cancelled.\n");
+ out_stream->Flush();
+ }
+
+ reader.SetIsDone (true);
+ }
+ got_interrupted = true;
+ break;
+
+ case eInputReaderEndOfFile:
+ reader.SetIsDone (true);
+ break;
+
+ case eInputReaderDone:
+ if (!got_interrupted && !batch_mode)
+ {
+ out_stream->Printf ("Stop hook #%" PRIu64 " added.\n", new_stop_hook->GetID());
+ out_stream->Flush();
+ }
+ break;
+ }
+
+ return bytes_len;
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ Target::StopHookSP new_hook_sp;
+ target->AddStopHook (new_hook_sp);
+
+ // First step, make the specifier.
+ std::unique_ptr<SymbolContextSpecifier> specifier_ap;
+ if (m_options.m_sym_ctx_specified)
+ {
+ specifier_ap.reset(new SymbolContextSpecifier(m_interpreter.GetDebugger().GetSelectedTarget()));
+
+ if (!m_options.m_module_name.empty())
+ {
+ specifier_ap->AddSpecification (m_options.m_module_name.c_str(), SymbolContextSpecifier::eModuleSpecified);
+ }
+
+ if (!m_options.m_class_name.empty())
+ {
+ specifier_ap->AddSpecification (m_options.m_class_name.c_str(), SymbolContextSpecifier::eClassOrNamespaceSpecified);
+ }
+
+ if (!m_options.m_file_name.empty())
+ {
+ specifier_ap->AddSpecification (m_options.m_file_name.c_str(), SymbolContextSpecifier::eFileSpecified);
+ }
+
+ if (m_options.m_line_start != 0)
+ {
+ specifier_ap->AddLineSpecification (m_options.m_line_start, SymbolContextSpecifier::eLineStartSpecified);
+ }
+
+ if (m_options.m_line_end != UINT_MAX)
+ {
+ specifier_ap->AddLineSpecification (m_options.m_line_end, SymbolContextSpecifier::eLineEndSpecified);
+ }
+
+ if (!m_options.m_function_name.empty())
+ {
+ specifier_ap->AddSpecification (m_options.m_function_name.c_str(), SymbolContextSpecifier::eFunctionSpecified);
+ }
+ }
+
+ if (specifier_ap.get())
+ new_hook_sp->SetSpecifier (specifier_ap.release());
+
+ // Next see if any of the thread options have been entered:
+
+ if (m_options.m_thread_specified)
+ {
+ ThreadSpec *thread_spec = new ThreadSpec();
+
+ if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID)
+ {
+ thread_spec->SetTID (m_options.m_thread_id);
+ }
+
+ if (m_options.m_thread_index != UINT32_MAX)
+ thread_spec->SetIndex (m_options.m_thread_index);
+
+ if (!m_options.m_thread_name.empty())
+ thread_spec->SetName (m_options.m_thread_name.c_str());
+
+ if (!m_options.m_queue_name.empty())
+ thread_spec->SetQueueName (m_options.m_queue_name.c_str());
+
+ new_hook_sp->SetThreadSpecifier (thread_spec);
+
+ }
+ if (m_options.m_use_one_liner)
+ {
+ // Use one-liner.
+ new_hook_sp->GetCommandPointer()->AppendString (m_options.m_one_liner.c_str());
+ result.AppendMessageWithFormat("Stop hook #%" PRIu64 " added.\n", new_hook_sp->GetID());
+ }
+ else
+ {
+ // Otherwise gather up the command list, we'll push an input reader and suck the data from that directly into
+ // the new stop hook's command string.
+ InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
+ if (!reader_sp)
+ {
+ result.AppendError("out of memory\n");
+ result.SetStatus (eReturnStatusFailed);
+ target->RemoveStopHookByID (new_hook_sp->GetID());
+ return false;
+ }
+
+ Error err (reader_sp->Initialize (CommandObjectTargetStopHookAdd::ReadCommandsCallbackFunction,
+ new_hook_sp.get(), // baton
+ eInputReaderGranularityLine, // token size, to pass to callback function
+ "DONE", // end token
+ "> ", // prompt
+ true)); // echo input
+ if (!err.Success())
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ target->RemoveStopHookByID (new_hook_sp->GetID());
+ return false;
+ }
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+private:
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectTargetStopHookAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "one-liner", 'o', required_argument, NULL, 0, eArgTypeOneLiner,
+ "Specify a one-line breakpoint command inline. Be sure to surround it with quotes." },
+ { LLDB_OPT_SET_ALL, false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName,
+ "Set the module within which the stop-hook is to be run."},
+ { LLDB_OPT_SET_ALL, false, "thread-index", 'x', required_argument, NULL, 0, eArgTypeThreadIndex,
+ "The stop hook is run only for the thread whose index matches this argument."},
+ { LLDB_OPT_SET_ALL, false, "thread-id", 't', required_argument, NULL, 0, eArgTypeThreadID,
+ "The stop hook is run only for the thread whose TID matches this argument."},
+ { LLDB_OPT_SET_ALL, false, "thread-name", 'T', required_argument, NULL, 0, eArgTypeThreadName,
+ "The stop hook is run only for the thread whose thread name matches this argument."},
+ { LLDB_OPT_SET_ALL, false, "queue-name", 'q', required_argument, NULL, 0, eArgTypeQueueName,
+ "The stop hook is run only for threads in the queue whose name is given by this argument."},
+ { LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
+ "Specify the source file within which the stop-hook is to be run." },
+ { LLDB_OPT_SET_1, false, "start-line", 'l', required_argument, NULL, 0, eArgTypeLineNum,
+ "Set the start of the line range for which the stop-hook is to be run."},
+ { LLDB_OPT_SET_1, false, "end-line", 'e', required_argument, NULL, 0, eArgTypeLineNum,
+ "Set the end of the line range for which the stop-hook is to be run."},
+ { LLDB_OPT_SET_2, false, "classname", 'c', required_argument, NULL, 0, eArgTypeClassName,
+ "Specify the class within which the stop-hook is to be run." },
+ { LLDB_OPT_SET_3, false, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
+ "Set the function name within which the stop hook will be run." },
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#pragma mark CommandObjectTargetStopHookDelete
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetStopHookDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetStopHookDelete : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetStopHookDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target stop-hook delete",
+ "Delete a stop-hook.",
+ "target stop-hook delete [<idx>]")
+ {
+ }
+
+ ~CommandObjectTargetStopHookDelete ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ // FIXME: see if we can use the breakpoint id style parser?
+ size_t num_args = command.GetArgumentCount();
+ if (num_args == 0)
+ {
+ if (!m_interpreter.Confirm ("Delete all stop hooks?", true))
+ {
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ target->RemoveAllStopHooks();
+ }
+ }
+ else
+ {
+ bool success;
+ for (size_t i = 0; i < num_args; i++)
+ {
+ lldb::user_id_t user_id = Args::StringToUInt32 (command.GetArgumentAtIndex(i), 0, 0, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("invalid stop hook id: \"%s\".\n", command.GetArgumentAtIndex(i));
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ success = target->RemoveStopHookByID (user_id);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("unknown stop hook id: \"%s\".\n", command.GetArgumentAtIndex(i));
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+};
+#pragma mark CommandObjectTargetStopHookEnableDisable
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetStopHookEnableDisable
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetStopHookEnableDisable : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetStopHookEnableDisable (CommandInterpreter &interpreter, bool enable, const char *name, const char *help, const char *syntax) :
+ CommandObjectParsed (interpreter,
+ name,
+ help,
+ syntax),
+ m_enable (enable)
+ {
+ }
+
+ ~CommandObjectTargetStopHookEnableDisable ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ // FIXME: see if we can use the breakpoint id style parser?
+ size_t num_args = command.GetArgumentCount();
+ bool success;
+
+ if (num_args == 0)
+ {
+ target->SetAllStopHooksActiveState (m_enable);
+ }
+ else
+ {
+ for (size_t i = 0; i < num_args; i++)
+ {
+ lldb::user_id_t user_id = Args::StringToUInt32 (command.GetArgumentAtIndex(i), 0, 0, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("invalid stop hook id: \"%s\".\n", command.GetArgumentAtIndex(i));
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ success = target->SetStopHookActiveStateByID (user_id, m_enable);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("unknown stop hook id: \"%s\".\n", command.GetArgumentAtIndex(i));
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+private:
+ bool m_enable;
+};
+
+#pragma mark CommandObjectTargetStopHookList
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetStopHookList
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetStopHookList : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetStopHookList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target stop-hook list",
+ "List all stop-hooks.",
+ "target stop-hook list [<type>]")
+ {
+ }
+
+ ~CommandObjectTargetStopHookList ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (!target)
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
+ }
+
+ size_t num_hooks = target->GetNumStopHooks ();
+ if (num_hooks == 0)
+ {
+ result.GetOutputStream().PutCString ("No stop hooks.\n");
+ }
+ else
+ {
+ for (size_t i = 0; i < num_hooks; i++)
+ {
+ Target::StopHookSP this_hook = target->GetStopHookAtIndex (i);
+ if (i > 0)
+ result.GetOutputStream().PutCString ("\n");
+ this_hook->GetDescription (&(result.GetOutputStream()), eDescriptionLevelFull);
+ }
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+};
+
+#pragma mark CommandObjectMultiwordTargetStopHooks
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordTargetStopHooks
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordTargetStopHooks : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordTargetStopHooks (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "target stop-hook",
+ "A set of commands for operating on debugger target stop-hooks.",
+ "target stop-hook <subcommand> [<subcommand-options>]")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTargetStopHookAdd (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTargetStopHookDelete (interpreter)));
+ LoadSubCommand ("disable", CommandObjectSP (new CommandObjectTargetStopHookEnableDisable (interpreter,
+ false,
+ "target stop-hook disable [<id>]",
+ "Disable a stop-hook.",
+ "target stop-hook disable")));
+ LoadSubCommand ("enable", CommandObjectSP (new CommandObjectTargetStopHookEnableDisable (interpreter,
+ true,
+ "target stop-hook enable [<id>]",
+ "Enable a stop-hook.",
+ "target stop-hook enable")));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTargetStopHookList (interpreter)));
+ }
+
+ ~CommandObjectMultiwordTargetStopHooks()
+ {
+ }
+};
+
+
+
+#pragma mark CommandObjectMultiwordTarget
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordTarget
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordTarget::CommandObjectMultiwordTarget (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "target",
+ "A set of commands for operating on debugger targets.",
+ "target <subcommand> [<subcommand-options>]")
+{
+
+ LoadSubCommand ("create", CommandObjectSP (new CommandObjectTargetCreate (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTargetDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTargetList (interpreter)));
+ LoadSubCommand ("select", CommandObjectSP (new CommandObjectTargetSelect (interpreter)));
+ LoadSubCommand ("stop-hook", CommandObjectSP (new CommandObjectMultiwordTargetStopHooks (interpreter)));
+ LoadSubCommand ("modules", CommandObjectSP (new CommandObjectTargetModules (interpreter)));
+ LoadSubCommand ("symbols", CommandObjectSP (new CommandObjectTargetSymbols (interpreter)));
+ LoadSubCommand ("variable", CommandObjectSP (new CommandObjectTargetVariable (interpreter)));
+}
+
+CommandObjectMultiwordTarget::~CommandObjectMultiwordTarget ()
+{
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.h
new file mode 100644
index 0000000..7b66378
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.h
@@ -0,0 +1,41 @@
+//===-- CommandObjectTarget.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_CommandObjectTarget_h_
+#define liblldb_CommandObjectTarget_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordTarget
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordTarget : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordTarget (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordTarget ();
+
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectTarget_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectThread.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectThread.cpp
new file mode 100644
index 0000000..b8657b4
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectThread.cpp
@@ -0,0 +1,1526 @@
+//===-- CommandObjectThread.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 "CommandObjectThread.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/SourceManager.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/LineEntry.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanStepInstruction.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Target/ThreadPlanStepRange.h"
+#include "lldb/Target/ThreadPlanStepInRange.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadBacktrace
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadBacktrace : public CommandObjectParsed
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ // Keep default values of all options in one place: OptionParsingStarting ()
+ OptionParsingStarting ();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'c':
+ {
+ bool success;
+ int32_t input_count = Args::StringToSInt32 (option_arg, -1, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid integer value for option '%c'", short_option);
+ if (input_count < -1)
+ m_count = UINT32_MAX;
+ else
+ m_count = input_count;
+ }
+ break;
+ case 's':
+ {
+ bool success;
+ m_start = Args::StringToUInt32 (option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid integer value for option '%c'", short_option);
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_count = UINT32_MAX;
+ m_start = 0;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ uint32_t m_count;
+ uint32_t m_start;
+ };
+
+ CommandObjectThreadBacktrace (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "thread backtrace",
+ "Show the stack for one or more threads. If no threads are specified, show the currently selected thread. Use the thread-index \"all\" to see all threads.",
+ NULL,
+ eFlagRequiresProcess |
+ eFlagRequiresThread |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData thread_idx_arg;
+
+ // Define the first (and only) variant of this arg.
+ thread_idx_arg.arg_type = eArgTypeThreadIndex;
+ thread_idx_arg.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (thread_idx_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectThreadBacktrace()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ Stream &strm = result.GetOutputStream();
+
+ // Don't show source context when doing backtraces.
+ const uint32_t num_frames_with_source = 0;
+ if (command.GetArgumentCount() == 0)
+ {
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+ // Thread::GetStatus() returns the number of frames shown.
+ if (thread->GetStatus (strm,
+ m_options.m_start,
+ m_options.m_count,
+ num_frames_with_source))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ }
+ else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ Mutex::Locker locker (process->GetThreadList().GetMutex());
+ uint32_t num_threads = process->GetThreadList().GetSize();
+ for (uint32_t i = 0; i < num_threads; i++)
+ {
+ ThreadSP thread_sp = process->GetThreadList().GetThreadAtIndex(i);
+ if (!thread_sp->GetStatus (strm,
+ m_options.m_start,
+ m_options.m_count,
+ num_frames_with_source))
+ {
+ result.AppendErrorWithFormat ("error displaying backtrace for thread: \"0x%4.4x\"\n", i);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (i < num_threads - 1)
+ result.AppendMessage("");
+
+ }
+ }
+ else
+ {
+ const size_t num_args = command.GetArgumentCount();
+ Process *process = m_exe_ctx.GetProcessPtr();
+ Mutex::Locker locker (process->GetThreadList().GetMutex());
+ std::vector<ThreadSP> thread_sps;
+
+ for (size_t i = 0; i < num_args; i++)
+ {
+ bool success;
+
+ uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx));
+
+ if (!thread_sps[i])
+ {
+ result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ }
+
+ for (uint32_t i = 0; i < num_args; i++)
+ {
+ if (!thread_sps[i]->GetStatus (strm,
+ m_options.m_start,
+ m_options.m_count,
+ num_frames_with_source))
+ {
+ result.AppendErrorWithFormat ("error displaying backtrace for thread: \"%s\"\n", command.GetArgumentAtIndex(i));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (i < num_args - 1)
+ result.AppendMessage("");
+ }
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectThreadBacktrace::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "count", 'c', required_argument, NULL, 0, eArgTypeCount, "How many frames to display (-1 for all)"},
+{ LLDB_OPT_SET_1, false, "start", 's', required_argument, NULL, 0, eArgTypeFrameIndex, "Frame in which to start the backtrace"},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+enum StepScope
+{
+ eStepScopeSource,
+ eStepScopeInstruction
+};
+
+class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ // Keep default values of all options in one place: OptionParsingStarting ()
+ OptionParsingStarting ();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ {
+ bool success;
+ m_avoid_no_debug = Args::StringToBoolean (option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid boolean value for option '%c'", short_option);
+ }
+ break;
+
+ case 'm':
+ {
+ OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
+ m_run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, error);
+ }
+ break;
+
+ case 'r':
+ {
+ m_avoid_regexp.clear();
+ m_avoid_regexp.assign(option_arg);
+ }
+ break;
+
+ case 't':
+ {
+ m_step_in_target.clear();
+ m_step_in_target.assign(option_arg);
+
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_avoid_no_debug = true;
+ m_run_mode = eOnlyDuringStepping;
+ m_avoid_regexp.clear();
+ m_step_in_target.clear();
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ bool m_avoid_no_debug;
+ RunMode m_run_mode;
+ std::string m_avoid_regexp;
+ std::string m_step_in_target;
+ };
+
+ CommandObjectThreadStepWithTypeAndScope (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax,
+ StepType step_type,
+ StepScope step_scope) :
+ CommandObjectParsed (interpreter, name, help, syntax,
+ eFlagRequiresProcess |
+ eFlagRequiresThread |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_step_type (step_type),
+ m_step_scope (step_scope),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData thread_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ thread_id_arg.arg_type = eArgTypeThreadID;
+ thread_id_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (thread_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectThreadStepWithTypeAndScope ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ bool synchronous_execution = m_interpreter.GetSynchronous();
+
+ const uint32_t num_threads = process->GetThreadList().GetSize();
+ Thread *thread = NULL;
+
+ if (command.GetArgumentCount() == 0)
+ {
+ thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL)
+ {
+ result.AppendError ("no selected thread in process");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ const char *thread_idx_cstr = command.GetArgumentAtIndex(0);
+ uint32_t step_thread_idx = Args::StringToUInt32 (thread_idx_cstr, LLDB_INVALID_INDEX32);
+ if (step_thread_idx == LLDB_INVALID_INDEX32)
+ {
+ result.AppendErrorWithFormat ("invalid thread index '%s'.\n", thread_idx_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ thread = process->GetThreadList().FindThreadByIndexID(step_thread_idx).get();
+ if (thread == NULL)
+ {
+ result.AppendErrorWithFormat ("Thread index %u is out of range (valid values are 0 - %u).\n",
+ step_thread_idx, num_threads);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ const bool abort_other_plans = false;
+ const lldb::RunMode stop_other_threads = m_options.m_run_mode;
+
+ // This is a bit unfortunate, but not all the commands in this command object support
+ // only while stepping, so I use the bool for them.
+ bool bool_stop_other_threads;
+ if (m_options.m_run_mode == eAllThreads)
+ bool_stop_other_threads = false;
+ else if (m_options.m_run_mode == eOnlyDuringStepping)
+ {
+ if (m_step_type == eStepTypeOut)
+ bool_stop_other_threads = false;
+ else
+ bool_stop_other_threads = true;
+ }
+ else
+ bool_stop_other_threads = true;
+
+ ThreadPlanSP new_plan_sp;
+
+ if (m_step_type == eStepTypeInto)
+ {
+ StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
+
+ if (frame->HasDebugInformation ())
+ {
+ new_plan_sp = thread->QueueThreadPlanForStepInRange (abort_other_plans,
+ frame->GetSymbolContext(eSymbolContextEverything).line_entry.range,
+ frame->GetSymbolContext(eSymbolContextEverything),
+ m_options.m_step_in_target.c_str(),
+ stop_other_threads,
+ m_options.m_avoid_no_debug);
+ if (new_plan_sp && !m_options.m_avoid_regexp.empty())
+ {
+ ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (new_plan_sp.get());
+ step_in_range_plan->SetAvoidRegexp(m_options.m_avoid_regexp.c_str());
+ }
+ }
+ else
+ new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads);
+
+ }
+ else if (m_step_type == eStepTypeOver)
+ {
+ StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
+
+ if (frame->HasDebugInformation())
+ new_plan_sp = thread->QueueThreadPlanForStepOverRange (abort_other_plans,
+ frame->GetSymbolContext(eSymbolContextEverything).line_entry.range,
+ frame->GetSymbolContext(eSymbolContextEverything),
+ stop_other_threads);
+ else
+ new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction (true,
+ abort_other_plans,
+ bool_stop_other_threads);
+
+ }
+ else if (m_step_type == eStepTypeTrace)
+ {
+ new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads);
+ }
+ else if (m_step_type == eStepTypeTraceOver)
+ {
+ new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction (true, abort_other_plans, bool_stop_other_threads);
+ }
+ else if (m_step_type == eStepTypeOut)
+ {
+ new_plan_sp = thread->QueueThreadPlanForStepOut (abort_other_plans,
+ NULL,
+ false,
+ bool_stop_other_threads,
+ eVoteYes,
+ eVoteNoOpinion,
+ thread->GetSelectedFrameIndex());
+ }
+ else
+ {
+ result.AppendError ("step type is not supported");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // If we got a new plan, then set it to be a master plan (User level Plans should be master plans
+ // so that they can be interruptible). Then resume the process.
+
+ if (new_plan_sp)
+ {
+ new_plan_sp->SetIsMasterPlan (true);
+ new_plan_sp->SetOkayToDiscard (false);
+
+ process->GetThreadList().SetSelectedThreadByID (thread->GetID());
+ process->Resume ();
+
+
+ if (synchronous_execution)
+ {
+ StateType state = process->WaitForProcessToStop (NULL);
+
+ //EventSP event_sp;
+ //StateType state = process->WaitForStateChangedEvents (NULL, event_sp);
+ //while (! StateIsStoppedState (state))
+ // {
+ // state = process->WaitForStateChangedEvents (NULL, event_sp);
+ // }
+ process->GetThreadList().SetSelectedThreadByID (thread->GetID());
+ result.SetDidChangeProcessState (true);
+ result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ }
+ }
+ else
+ {
+ result.AppendError ("Couldn't find thread plan to implement step type.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+protected:
+ StepType m_step_type;
+ StepScope m_step_scope;
+ CommandOptions m_options;
+};
+
+static OptionEnumValueElement
+g_tri_running_mode[] =
+{
+{ eOnlyThisThread, "this-thread", "Run only this thread"},
+{ eAllThreads, "all-threads", "Run all threads"},
+{ eOnlyDuringStepping, "while-stepping", "Run only this thread while stepping"},
+{ 0, NULL, NULL }
+};
+
+static OptionEnumValueElement
+g_duo_running_mode[] =
+{
+{ eOnlyThisThread, "this-thread", "Run only this thread"},
+{ eAllThreads, "all-threads", "Run all threads"},
+{ 0, NULL, NULL }
+};
+
+OptionDefinition
+CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "avoid-no-debug", 'a', required_argument, NULL, 0, eArgTypeBoolean, "A boolean value that sets whether step-in will step over functions with no debug information."},
+{ LLDB_OPT_SET_1, false, "run-mode", 'm', required_argument, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread."},
+{ LLDB_OPT_SET_1, false, "step-over-regexp",'r', required_argument, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in."},
+{ LLDB_OPT_SET_1, false, "step-in-target", 't', required_argument, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadContinue
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadContinue : public CommandObjectParsed
+{
+public:
+
+ CommandObjectThreadContinue (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "thread continue",
+ "Continue execution of one or more threads in an active process.",
+ NULL,
+ eFlagRequiresThread |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData thread_idx_arg;
+
+ // Define the first (and only) variant of this arg.
+ thread_idx_arg.arg_type = eArgTypeThreadIndex;
+ thread_idx_arg.arg_repetition = eArgRepeatPlus;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (thread_idx_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ virtual
+ ~CommandObjectThreadContinue ()
+ {
+ }
+
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ bool synchronous_execution = m_interpreter.GetSynchronous ();
+
+ if (!m_interpreter.GetDebugger().GetSelectedTarget().get())
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ {
+ result.AppendError ("no process exists. Cannot continue");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ StateType state = process->GetState();
+ if ((state == eStateCrashed) || (state == eStateStopped) || (state == eStateSuspended))
+ {
+ Mutex::Locker locker (process->GetThreadList().GetMutex());
+ const uint32_t num_threads = process->GetThreadList().GetSize();
+ const size_t argc = command.GetArgumentCount();
+ if (argc > 0)
+ {
+ std::vector<Thread *> resume_threads;
+ for (uint32_t i=0; i<argc; ++i)
+ {
+ bool success;
+ const int base = 0;
+ uint32_t thread_idx = Args::StringToUInt32 (command.GetArgumentAtIndex(i), LLDB_INVALID_INDEX32, base, &success);
+ if (success)
+ {
+ Thread *thread = process->GetThreadList().FindThreadByIndexID(thread_idx).get();
+
+ if (thread)
+ {
+ resume_threads.push_back(thread);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("invalid thread index %u.\n", thread_idx);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("invalid thread index argument: \"%s\".\n", command.GetArgumentAtIndex(i));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ if (resume_threads.empty())
+ {
+ result.AppendError ("no valid thread indexes were specified");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ if (resume_threads.size() == 1)
+ result.AppendMessageWithFormat ("Resuming thread: ");
+ else
+ result.AppendMessageWithFormat ("Resuming threads: ");
+
+ for (uint32_t idx=0; idx<num_threads; ++idx)
+ {
+ Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
+ std::vector<Thread *>::iterator this_thread_pos = find(resume_threads.begin(), resume_threads.end(), thread);
+
+ if (this_thread_pos != resume_threads.end())
+ {
+ resume_threads.erase(this_thread_pos);
+ if (resume_threads.size() > 0)
+ result.AppendMessageWithFormat ("%u, ", thread->GetIndexID());
+ else
+ result.AppendMessageWithFormat ("%u ", thread->GetIndexID());
+
+ thread->SetResumeState (eStateRunning);
+ }
+ else
+ {
+ thread->SetResumeState (eStateSuspended);
+ }
+ }
+ result.AppendMessageWithFormat ("in process %" PRIu64 "\n", process->GetID());
+ }
+ }
+ else
+ {
+ Thread *current_thread = process->GetThreadList().GetSelectedThread().get();
+ if (current_thread == NULL)
+ {
+ result.AppendError ("the process doesn't have a current thread");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ // Set the actions that the threads should each take when resuming
+ for (uint32_t idx=0; idx<num_threads; ++idx)
+ {
+ Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
+ if (thread == current_thread)
+ {
+ result.AppendMessageWithFormat ("Resuming thread 0x%4.4" PRIx64 " in process %" PRIu64 "\n", thread->GetID(), process->GetID());
+ thread->SetResumeState (eStateRunning);
+ }
+ else
+ {
+ thread->SetResumeState (eStateSuspended);
+ }
+ }
+ }
+
+ Error error (process->Resume());
+ if (error.Success())
+ {
+ result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
+ if (synchronous_execution)
+ {
+ state = process->WaitForProcessToStop (NULL);
+
+ result.SetDidChangeProcessState (true);
+ result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Failed to resume process: %s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Process cannot be continued from its current state (%s).\n",
+ StateAsCString(state));
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadUntil
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadUntil : public CommandObjectParsed
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+ uint32_t m_thread_idx;
+ uint32_t m_frame_idx;
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_thread_idx(LLDB_INVALID_THREAD_ID),
+ m_frame_idx(LLDB_INVALID_FRAME_ID)
+ {
+ // Keep default values of all options in one place: OptionParsingStarting ()
+ OptionParsingStarting ();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 't':
+ {
+ m_thread_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_INDEX32);
+ if (m_thread_idx == LLDB_INVALID_INDEX32)
+ {
+ error.SetErrorStringWithFormat ("invalid thread index '%s'", option_arg);
+ }
+ }
+ break;
+ case 'f':
+ {
+ m_frame_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_FRAME_ID);
+ if (m_frame_idx == LLDB_INVALID_FRAME_ID)
+ {
+ error.SetErrorStringWithFormat ("invalid frame index '%s'", option_arg);
+ }
+ }
+ break;
+ case 'm':
+ {
+ OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
+ lldb::RunMode run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, error);
+
+ if (error.Success())
+ {
+ if (run_mode == eAllThreads)
+ m_stop_others = false;
+ else
+ m_stop_others = true;
+ }
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_thread_idx = LLDB_INVALID_THREAD_ID;
+ m_frame_idx = 0;
+ m_stop_others = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ uint32_t m_step_thread_idx;
+ bool m_stop_others;
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ };
+
+ CommandObjectThreadUntil (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "thread until",
+ "Run the current or specified thread until it reaches a given line number or leaves the current function.",
+ NULL,
+ eFlagRequiresThread |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData line_num_arg;
+
+ // Define the first (and only) variant of this arg.
+ line_num_arg.arg_type = eArgTypeLineNum;
+ line_num_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (line_num_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ virtual
+ ~CommandObjectThreadUntil ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ bool synchronous_execution = m_interpreter.GetSynchronous ();
+
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ {
+ result.AppendError ("need a valid process to step");
+ result.SetStatus (eReturnStatusFailed);
+
+ }
+ else
+ {
+ Thread *thread = NULL;
+ uint32_t line_number;
+
+ if (command.GetArgumentCount() != 1)
+ {
+ result.AppendErrorWithFormat ("No line number provided:\n%s", GetSyntax());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ line_number = Args::StringToUInt32 (command.GetArgumentAtIndex(0), UINT32_MAX);
+ if (line_number == UINT32_MAX)
+ {
+ result.AppendErrorWithFormat ("invalid line number: '%s'.\n", command.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID)
+ {
+ thread = process->GetThreadList().GetSelectedThread().get();
+ }
+ else
+ {
+ thread = process->GetThreadList().FindThreadByIndexID(m_options.m_thread_idx).get();
+ }
+
+ if (thread == NULL)
+ {
+ const uint32_t num_threads = process->GetThreadList().GetSize();
+ result.AppendErrorWithFormat ("Thread index %u is out of range (valid values are 0 - %u).\n",
+ m_options.m_thread_idx,
+ num_threads);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const bool abort_other_plans = false;
+
+ StackFrame *frame = thread->GetStackFrameAtIndex(m_options.m_frame_idx).get();
+ if (frame == NULL)
+ {
+
+ result.AppendErrorWithFormat ("Frame index %u is out of range for thread %u.\n",
+ m_options.m_frame_idx,
+ m_options.m_thread_idx);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ThreadPlanSP new_plan_sp;
+
+ if (frame->HasDebugInformation ())
+ {
+ // Finally we got here... Translate the given line number to a bunch of addresses:
+ SymbolContext sc(frame->GetSymbolContext (eSymbolContextCompUnit));
+ LineTable *line_table = NULL;
+ if (sc.comp_unit)
+ line_table = sc.comp_unit->GetLineTable();
+
+ if (line_table == NULL)
+ {
+ result.AppendErrorWithFormat ("Failed to resolve the line table for frame %u of thread index %u.\n",
+ m_options.m_frame_idx, m_options.m_thread_idx);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ LineEntry function_start;
+ uint32_t index_ptr = 0, end_ptr;
+ std::vector<addr_t> address_list;
+
+ // Find the beginning & end index of the
+ AddressRange fun_addr_range = sc.function->GetAddressRange();
+ Address fun_start_addr = fun_addr_range.GetBaseAddress();
+ line_table->FindLineEntryByAddress (fun_start_addr, function_start, &index_ptr);
+
+ Address fun_end_addr(fun_start_addr.GetSection(),
+ fun_start_addr.GetOffset() + fun_addr_range.GetByteSize());
+ line_table->FindLineEntryByAddress (fun_end_addr, function_start, &end_ptr);
+
+ bool all_in_function = true;
+
+ while (index_ptr <= end_ptr)
+ {
+ LineEntry line_entry;
+ const bool exact = false;
+ index_ptr = sc.comp_unit->FindLineEntry(index_ptr, line_number, sc.comp_unit, exact, &line_entry);
+ if (index_ptr == UINT32_MAX)
+ break;
+
+ addr_t address = line_entry.range.GetBaseAddress().GetLoadAddress(target);
+ if (address != LLDB_INVALID_ADDRESS)
+ {
+ if (fun_addr_range.ContainsLoadAddress (address, target))
+ address_list.push_back (address);
+ else
+ all_in_function = false;
+ }
+ index_ptr++;
+ }
+
+ if (address_list.size() == 0)
+ {
+ if (all_in_function)
+ result.AppendErrorWithFormat ("No line entries matching until target.\n");
+ else
+ result.AppendErrorWithFormat ("Until target outside of the current function.\n");
+
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ new_plan_sp = thread->QueueThreadPlanForStepUntil (abort_other_plans,
+ &address_list.front(),
+ address_list.size(),
+ m_options.m_stop_others,
+ m_options.m_frame_idx);
+ // User level plans should be master plans so they can be interrupted (e.g. by hitting a breakpoint)
+ // and other plans executed by the user (stepping around the breakpoint) and then a "continue"
+ // will resume the original plan.
+ new_plan_sp->SetIsMasterPlan (true);
+ new_plan_sp->SetOkayToDiscard(false);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Frame index %u of thread %u has no debug information.\n",
+ m_options.m_frame_idx,
+ m_options.m_thread_idx);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+
+ }
+
+ process->GetThreadList().SetSelectedThreadByID (m_options.m_thread_idx);
+ Error error (process->Resume ());
+ if (error.Success())
+ {
+ result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
+ if (synchronous_execution)
+ {
+ StateType state = process->WaitForProcessToStop (NULL);
+
+ result.SetDidChangeProcessState (true);
+ result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+
+};
+
+OptionDefinition
+CommandObjectThreadUntil::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "frame", 'f', required_argument, NULL, 0, eArgTypeFrameIndex, "Frame index for until operation - defaults to 0"},
+{ LLDB_OPT_SET_1, false, "thread", 't', required_argument, NULL, 0, eArgTypeThreadIndex, "Thread index for the thread for until operation"},
+{ LLDB_OPT_SET_1, false, "run-mode",'m', required_argument, g_duo_running_mode, 0, eArgTypeRunMode,"Determine how to run other threads while stepping this one"},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadSelect
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadSelect : public CommandObjectParsed
+{
+public:
+
+ CommandObjectThreadSelect (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "thread select",
+ "Select a thread as the currently active thread.",
+ NULL,
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused )
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData thread_idx_arg;
+
+ // Define the first (and only) variant of this arg.
+ thread_idx_arg.arg_type = eArgTypeThreadIndex;
+ thread_idx_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (thread_idx_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ virtual
+ ~CommandObjectThreadSelect ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ {
+ result.AppendError ("no process");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else if (command.GetArgumentCount() != 1)
+ {
+ result.AppendErrorWithFormat("'%s' takes exactly one thread index argument:\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ uint32_t index_id = Args::StringToUInt32(command.GetArgumentAtIndex(0), 0, 0);
+
+ Thread *new_thread = process->GetThreadList().FindThreadByIndexID(index_id).get();
+ if (new_thread == NULL)
+ {
+ result.AppendErrorWithFormat ("invalid thread #%s.\n", command.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ process->GetThreadList().SetSelectedThreadByID(new_thread->GetID(), true);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+
+ return result.Succeeded();
+ }
+
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadList
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadList : public CommandObjectParsed
+{
+public:
+
+
+ CommandObjectThreadList (CommandInterpreter &interpreter):
+ CommandObjectParsed (interpreter,
+ "thread list",
+ "Show a summary of all current threads in a process.",
+ "thread list",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused )
+ {
+ }
+
+ ~CommandObjectThreadList()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Stream &strm = result.GetOutputStream();
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ Process *process = m_exe_ctx.GetProcessPtr();
+ const bool only_threads_with_stop_reason = false;
+ const uint32_t start_frame = 0;
+ const uint32_t num_frames = 0;
+ const uint32_t num_frames_with_source = 0;
+ process->GetStatus(strm);
+ process->GetThreadStatus (strm,
+ only_threads_with_stop_reason,
+ start_frame,
+ num_frames,
+ num_frames_with_source);
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadReturn
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadReturn : public CommandObjectRaw
+{
+public:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_from_expression (false)
+ {
+ // Keep default values of all options in one place: OptionParsingStarting ()
+ OptionParsingStarting ();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'x':
+ {
+ bool success;
+ bool tmp_value = Args::StringToBoolean (option_arg, false, &success);
+ if (success)
+ m_from_expression = tmp_value;
+ else
+ {
+ error.SetErrorStringWithFormat ("invalid boolean value '%s' for 'x' option", option_arg);
+ }
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_from_expression = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ bool m_from_expression;
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ };
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ CommandObjectThreadReturn (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "thread return",
+ "Return from the currently selected frame, short-circuiting execution of the frames below it, with an optional return value,"
+ " or with the -x option from the innermost function evaluation.",
+ "thread return",
+ eFlagRequiresFrame |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData expression_arg;
+
+ // Define the first (and only) variant of this arg.
+ expression_arg.arg_type = eArgTypeExpression;
+ expression_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (expression_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+
+ }
+
+ ~CommandObjectThreadReturn()
+ {
+ }
+
+protected:
+
+ bool DoExecute
+ (
+ const char *command,
+ CommandReturnObject &result
+ )
+ {
+ // I am going to handle this by hand, because I don't want you to have to say:
+ // "thread return -- -5".
+ if (command[0] == '-' && command[1] == 'x')
+ {
+ if (command && command[2] != '\0')
+ result.AppendWarning("Return values ignored when returning from user called expressions");
+
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+ Error error;
+ error = thread->UnwindInnermostExpression();
+ if (!error.Success())
+ {
+ result.AppendErrorWithFormat ("Unwinding expression failed - %s.", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ bool success = thread->SetSelectedFrameByIndexNoisily (0, result.GetOutputStream());
+ if (success)
+ {
+ m_exe_ctx.SetFrameSP(thread->GetSelectedFrame ());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Could not select 0th frame after unwinding expression.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ return result.Succeeded();
+ }
+
+ ValueObjectSP return_valobj_sp;
+
+ StackFrameSP frame_sp = m_exe_ctx.GetFrameSP();
+ uint32_t frame_idx = frame_sp->GetFrameIndex();
+
+ if (frame_sp->IsInlined())
+ {
+ result.AppendError("Don't know how to return from inlined frames.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command && command[0] != '\0')
+ {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ EvaluateExpressionOptions options;
+
+ options.SetUnwindOnError(true);
+ options.SetUseDynamic(eNoDynamicValues);
+
+ ExecutionResults exe_results = eExecutionSetupError;
+ exe_results = target->EvaluateExpression (command,
+ frame_sp.get(),
+ return_valobj_sp,
+ options);
+ if (exe_results != eExecutionCompleted)
+ {
+ if (return_valobj_sp)
+ result.AppendErrorWithFormat("Error evaluating result expression: %s", return_valobj_sp->GetError().AsCString());
+ else
+ result.AppendErrorWithFormat("Unknown error evaluating result expression.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+
+ }
+ }
+
+ Error error;
+ ThreadSP thread_sp = m_exe_ctx.GetThreadSP();
+ const bool broadcast = true;
+ error = thread_sp->ReturnFromFrame (frame_sp, return_valobj_sp, broadcast);
+ if (!error.Success())
+ {
+ result.AppendErrorWithFormat("Error returning from frame %d of thread %d: %s.", frame_idx, thread_sp->GetIndexID(), error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return true;
+ }
+
+ CommandOptions m_options;
+
+};
+OptionDefinition
+CommandObjectThreadReturn::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "from-expression", 'x', no_argument, NULL, 0, eArgTypeNone, "Return from the innermost expression evaluation."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordThread
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "thread",
+ "A set of commands for operating on one or more threads within a running process.",
+ "thread <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand ("backtrace", CommandObjectSP (new CommandObjectThreadBacktrace (interpreter)));
+ LoadSubCommand ("continue", CommandObjectSP (new CommandObjectThreadContinue (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectThreadList (interpreter)));
+ LoadSubCommand ("return", CommandObjectSP (new CommandObjectThreadReturn (interpreter)));
+ LoadSubCommand ("select", CommandObjectSP (new CommandObjectThreadSelect (interpreter)));
+ LoadSubCommand ("until", CommandObjectSP (new CommandObjectThreadUntil (interpreter)));
+ LoadSubCommand ("step-in", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
+ interpreter,
+ "thread step-in",
+ "Source level single step in specified thread (current thread, if none specified).",
+ NULL,
+ eStepTypeInto,
+ eStepScopeSource)));
+
+ LoadSubCommand ("step-out", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
+ interpreter,
+ "thread step-out",
+ "Finish executing the function of the currently selected frame and return to its call site in specified thread (current thread, if none specified).",
+ NULL,
+ eStepTypeOut,
+ eStepScopeSource)));
+
+ LoadSubCommand ("step-over", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
+ interpreter,
+ "thread step-over",
+ "Source level single step in specified thread (current thread, if none specified), stepping over calls.",
+ NULL,
+ eStepTypeOver,
+ eStepScopeSource)));
+
+ LoadSubCommand ("step-inst", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
+ interpreter,
+ "thread step-inst",
+ "Single step one instruction in specified thread (current thread, if none specified).",
+ NULL,
+ eStepTypeTrace,
+ eStepScopeInstruction)));
+
+ LoadSubCommand ("step-inst-over", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
+ interpreter,
+ "thread step-inst-over",
+ "Single step one instruction in specified thread (current thread, if none specified), stepping over calls.",
+ NULL,
+ eStepTypeTraceOver,
+ eStepScopeInstruction)));
+}
+
+CommandObjectMultiwordThread::~CommandObjectMultiwordThread ()
+{
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectThread.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectThread.h
new file mode 100644
index 0000000..52902ee
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectThread.h
@@ -0,0 +1,34 @@
+//===-- CommandObjectThread.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_CommandObjectThread_h_
+#define liblldb_CommandObjectThread_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+class CommandObjectMultiwordThread : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordThread (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordThread ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectThread_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectType.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectType.cpp
new file mode 100644
index 0000000..b300f21
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectType.cpp
@@ -0,0 +1,4112 @@
+//===-- CommandObjectType.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 "CommandObjectType.h"
+
+// C Includes
+
+#include <ctype.h>
+
+// C++ Includes
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/InputReaderEZ.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionGroupFormat.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+class ScriptAddOptions
+{
+
+public:
+
+ TypeSummaryImpl::Flags m_flags;
+
+ StringList m_target_types;
+ StringList m_user_source;
+
+ bool m_regex;
+
+ ConstString m_name;
+
+ std::string m_category;
+
+ ScriptAddOptions(const TypeSummaryImpl::Flags& flags,
+ bool regx,
+ const ConstString& name,
+ std::string catg) :
+ m_flags(flags),
+ m_regex(regx),
+ m_name(name),
+ m_category(catg)
+ {
+ }
+
+ typedef std::shared_ptr<ScriptAddOptions> SharedPointer;
+
+};
+
+class SynthAddOptions
+{
+
+public:
+
+ bool m_skip_pointers;
+ bool m_skip_references;
+ bool m_cascade;
+ bool m_regex;
+ StringList m_user_source;
+ StringList m_target_types;
+
+ std::string m_category;
+
+ SynthAddOptions(bool sptr,
+ bool sref,
+ bool casc,
+ bool regx,
+ std::string catg) :
+ m_skip_pointers(sptr),
+ m_skip_references(sref),
+ m_cascade(casc),
+ m_regex(regx),
+ m_user_source(),
+ m_target_types(),
+ m_category(catg)
+ {
+ }
+
+ typedef std::shared_ptr<SynthAddOptions> SharedPointer;
+
+};
+
+
+
+class CommandObjectTypeSummaryAdd : public CommandObjectParsed
+{
+
+private:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg);
+
+ void
+ OptionParsingStarting ();
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ TypeSummaryImpl::Flags m_flags;
+ bool m_regex;
+ std::string m_format_string;
+ ConstString m_name;
+ std::string m_python_script;
+ std::string m_python_function;
+ bool m_is_add_script;
+ std::string m_category;
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ void
+ CollectPythonScript(ScriptAddOptions *options,
+ CommandReturnObject &result);
+
+ bool
+ Execute_ScriptSummary (Args& command, CommandReturnObject &result);
+
+ bool
+ Execute_StringSummary (Args& command, CommandReturnObject &result);
+
+public:
+
+ enum SummaryFormatType
+ {
+ eRegularSummary,
+ eRegexSummary,
+ eNamedSummary
+ };
+
+ CommandObjectTypeSummaryAdd (CommandInterpreter &interpreter);
+
+ ~CommandObjectTypeSummaryAdd ()
+ {
+ }
+
+ static bool
+ AddSummary(ConstString type_name,
+ lldb::TypeSummaryImplSP entry,
+ SummaryFormatType type,
+ std::string category,
+ Error* error = NULL);
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result);
+
+};
+
+class CommandObjectTypeSynthAdd : public CommandObjectParsed
+{
+
+private:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+ bool success;
+
+ switch (short_option)
+ {
+ case 'C':
+ m_cascade = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for cascade: %s", option_arg);
+ break;
+ case 'P':
+ handwrite_python = true;
+ break;
+ case 'l':
+ m_class_name = std::string(option_arg);
+ is_class_based = true;
+ break;
+ case 'p':
+ m_skip_pointers = true;
+ break;
+ case 'r':
+ m_skip_references = true;
+ break;
+ case 'w':
+ m_category = std::string(option_arg);
+ break;
+ case 'x':
+ m_regex = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_cascade = true;
+ m_class_name = "";
+ m_skip_pointers = false;
+ m_skip_references = false;
+ m_category = "default";
+ is_class_based = false;
+ handwrite_python = false;
+ m_regex = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_cascade;
+ bool m_skip_references;
+ bool m_skip_pointers;
+ std::string m_class_name;
+ bool m_input_python;
+ std::string m_category;
+
+ bool is_class_based;
+
+ bool handwrite_python;
+
+ bool m_regex;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ void
+ CollectPythonScript (SynthAddOptions *options,
+ CommandReturnObject &result);
+ bool
+ Execute_HandwritePython (Args& command, CommandReturnObject &result);
+
+ bool
+ Execute_PythonClass (Args& command, CommandReturnObject &result);
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result);
+
+public:
+
+ enum SynthFormatType
+ {
+ eRegularSynth,
+ eRegexSynth
+ };
+
+ CommandObjectTypeSynthAdd (CommandInterpreter &interpreter);
+
+ ~CommandObjectTypeSynthAdd ()
+ {
+ }
+
+ static bool
+ AddSynth(ConstString type_name,
+ lldb::SyntheticChildrenSP entry,
+ SynthFormatType type,
+ std::string category_name,
+ Error* error);
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeFormatAdd
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeFormatAdd : public CommandObjectParsed
+{
+
+private:
+
+ class CommandOptions : public OptionGroup
+ {
+ public:
+
+ CommandOptions () :
+ OptionGroup()
+ {
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter)
+ {
+ m_cascade = true;
+ m_skip_pointers = false;
+ m_skip_references = false;
+ }
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value)
+ {
+ Error error;
+ const int short_option = g_option_table[option_idx].short_option;
+ bool success;
+
+ switch (short_option)
+ {
+ case 'C':
+ m_cascade = Args::StringToBoolean(option_value, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for cascade: %s", option_value);
+ break;
+ case 'p':
+ m_skip_pointers = true;
+ break;
+ case 'r':
+ m_skip_references = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_cascade;
+ bool m_skip_references;
+ bool m_skip_pointers;
+ };
+
+ OptionGroupOptions m_option_group;
+ OptionGroupFormat m_format_options;
+ CommandOptions m_command_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+public:
+ CommandObjectTypeFormatAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type format add",
+ "Add a new formatting style for a type.",
+ NULL),
+ m_option_group (interpreter),
+ m_format_options (eFormatInvalid),
+ m_command_options ()
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlus;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ SetHelpLong(
+ "Some examples of using this command.\n"
+ "We use as reference the following snippet of code:\n"
+ "\n"
+ "typedef int Aint;\n"
+ "typedef float Afloat;\n"
+ "typedef Aint Bint;\n"
+ "typedef Afloat Bfloat;\n"
+ "\n"
+ "Aint ix = 5;\n"
+ "Bint iy = 5;\n"
+ "\n"
+ "Afloat fx = 3.14;\n"
+ "BFloat fy = 3.14;\n"
+ "\n"
+ "Typing:\n"
+ "type format add -f hex AInt\n"
+ "frame variable iy\n"
+ "will produce an hex display of iy, because no formatter is available for Bint and the one for Aint is used instead\n"
+ "To prevent this type\n"
+ "type format add -f hex -C no AInt\n"
+ "\n"
+ "A similar reasoning applies to\n"
+ "type format add -f hex -C no float -p\n"
+ "which now prints all floats and float&s as hexadecimal, but does not format float*s\n"
+ "and does not change the default display for Afloat and Bfloat objects.\n"
+ );
+
+ // Add the "--format" to all options groups
+ m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_ALL);
+ m_option_group.Append (&m_command_options);
+ m_option_group.Finalize();
+
+ }
+
+ ~CommandObjectTypeFormatAdd ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1)
+ {
+ result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const Format format = m_format_options.GetFormat();
+ if (format == eFormatInvalid)
+ {
+ result.AppendErrorWithFormat ("%s needs a valid format.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ TypeFormatImplSP entry;
+
+ entry.reset(new TypeFormatImpl(format,
+ TypeFormatImpl::Flags().SetCascades(m_command_options.m_cascade).
+ SetSkipPointers(m_command_options.m_skip_pointers).
+ SetSkipReferences(m_command_options.m_skip_references)));
+
+ // now I have a valid format, let's add it to every type
+
+ for (size_t i = 0; i < argc; i++)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ ConstString typeCS(typeA);
+ if (typeCS)
+ DataVisualization::ValueFormats::Add(typeCS, entry);
+ else
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+};
+
+OptionDefinition
+CommandObjectTypeFormatAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
+ { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "skip-references", 'r', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."},
+};
+
+
+uint32_t
+CommandObjectTypeFormatAdd::CommandOptions::GetNumDefinitions ()
+{
+ return sizeof(g_option_table) / sizeof (OptionDefinition);
+}
+
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeFormatDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeFormatDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectTypeFormatDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type format delete",
+ "Delete an existing formatting style for a type.",
+ NULL)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlain;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ }
+
+ ~CommandObjectTypeFormatDelete ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const char* typeA = command.GetArgumentAtIndex(0);
+ ConstString typeCS(typeA);
+
+ if (!typeCS)
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+
+ if (DataVisualization::ValueFormats::Delete(typeCS))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no custom format for %s.\n", typeA);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeFormatClear
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeFormatClear : public CommandObjectParsed
+{
+public:
+ CommandObjectTypeFormatClear (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type format clear",
+ "Delete all existing format styles.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectTypeFormatClear ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ DataVisualization::ValueFormats::Clear();
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeFormatList
+//-------------------------------------------------------------------------
+
+bool CommandObjectTypeFormatList_LoopCallback(void* pt2self, ConstString type, const lldb::TypeFormatImplSP& entry);
+
+class CommandObjectTypeFormatList;
+
+struct CommandObjectTypeFormatList_LoopCallbackParam {
+ CommandObjectTypeFormatList* self;
+ CommandReturnObject* result;
+ RegularExpression* regex;
+ CommandObjectTypeFormatList_LoopCallbackParam(CommandObjectTypeFormatList* S, CommandReturnObject* R,
+ RegularExpression* X = NULL) : self(S), result(R), regex(X) {}
+};
+
+class CommandObjectTypeFormatList : public CommandObjectParsed
+{
+public:
+ CommandObjectTypeFormatList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type format list",
+ "Show a list of current formatting styles.",
+ NULL)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatOptional;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+ }
+
+ ~CommandObjectTypeFormatList ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ CommandObjectTypeFormatList_LoopCallbackParam *param;
+
+ if (argc == 1)
+ {
+ RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
+ regex->Compile(command.GetArgumentAtIndex(0));
+ param = new CommandObjectTypeFormatList_LoopCallbackParam(this,&result,regex);
+ }
+ else
+ param = new CommandObjectTypeFormatList_LoopCallbackParam(this,&result);
+ DataVisualization::ValueFormats::LoopThrough(CommandObjectTypeFormatList_LoopCallback, param);
+ delete param;
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+private:
+
+ bool
+ LoopCallback (ConstString type,
+ const lldb::TypeFormatImplSP& entry,
+ RegularExpression* regex,
+ CommandReturnObject *result)
+ {
+ if (regex == NULL || regex->Execute(type.AsCString()))
+ {
+ result->GetOutputStream().Printf ("%s: %s\n", type.AsCString(),
+ entry->GetDescription().c_str());
+ }
+ return true;
+ }
+
+ friend bool CommandObjectTypeFormatList_LoopCallback(void* pt2self, ConstString type, const lldb::TypeFormatImplSP& entry);
+
+};
+
+bool
+CommandObjectTypeFormatList_LoopCallback (
+ void* pt2self,
+ ConstString type,
+ const lldb::TypeFormatImplSP& entry)
+{
+ CommandObjectTypeFormatList_LoopCallbackParam* param = (CommandObjectTypeFormatList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(type, entry, param->regex, param->result);
+}
+
+
+#ifndef LLDB_DISABLE_PYTHON
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSummaryAdd
+//-------------------------------------------------------------------------
+
+static const char *g_summary_addreader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n"
+ "def function (valobj,internal_dict):\n"
+ " \"\"\"valobj: an SBValue which you want to provide a summary for\n"
+ " internal_dict: an LLDB support object not to be used\"\"\"";
+
+class TypeScriptAddInputReader : public InputReaderEZ
+{
+private:
+ DISALLOW_COPY_AND_ASSIGN (TypeScriptAddInputReader);
+public:
+ TypeScriptAddInputReader(Debugger& debugger) :
+ InputReaderEZ(debugger)
+ {}
+
+ virtual
+ ~TypeScriptAddInputReader()
+ {
+ }
+
+ virtual void ActivateHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+ if (!batch_mode)
+ {
+ out_stream->Printf ("%s\n", g_summary_addreader_instructions);
+ if (data.reader.GetPrompt())
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+
+ virtual void ReactivateHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+ if (data.reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+ virtual void GotTokenHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+ if (data.bytes && data.bytes_len && data.baton)
+ {
+ ((ScriptAddOptions*)data.baton)->m_user_source.AppendString(data.bytes, data.bytes_len);
+ }
+ if (!data.reader.IsDone() && data.reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+ virtual void InterruptHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+ data.reader.SetIsDone (true);
+ if (!batch_mode)
+ {
+ out_stream->Printf ("Warning: No command attached to breakpoint.\n");
+ out_stream->Flush();
+ }
+ }
+ virtual void EOFHandler(HandlerData& data)
+ {
+ data.reader.SetIsDone (true);
+ }
+ virtual void DoneHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream();
+ ScriptAddOptions *options_ptr = ((ScriptAddOptions*)data.baton);
+ if (!options_ptr)
+ {
+ out_stream->Printf ("internal synchronization information missing or invalid.\n");
+ out_stream->Flush();
+ return;
+ }
+
+ ScriptAddOptions::SharedPointer options(options_ptr); // this will ensure that we get rid of the pointer when going out of scope
+
+ ScriptInterpreter *interpreter = data.reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (!interpreter)
+ {
+ out_stream->Printf ("no script interpreter.\n");
+ out_stream->Flush();
+ return;
+ }
+ std::string funct_name_str;
+ if (!interpreter->GenerateTypeScriptFunction (options->m_user_source,
+ funct_name_str))
+ {
+ out_stream->Printf ("unable to generate a function.\n");
+ out_stream->Flush();
+ return;
+ }
+ if (funct_name_str.empty())
+ {
+ out_stream->Printf ("unable to obtain a valid function name from the script interpreter.\n");
+ out_stream->Flush();
+ return;
+ }
+ // now I have a valid function name, let's add this as script for every type in the list
+
+ TypeSummaryImplSP script_format;
+ script_format.reset(new ScriptSummaryFormat(options->m_flags,
+ funct_name_str.c_str(),
+ options->m_user_source.CopyList(" ").c_str()));
+
+ Error error;
+
+ for (size_t i = 0; i < options->m_target_types.GetSize(); i++)
+ {
+ const char *type_name = options->m_target_types.GetStringAtIndex(i);
+ CommandObjectTypeSummaryAdd::AddSummary(ConstString(type_name),
+ script_format,
+ (options->m_regex ? CommandObjectTypeSummaryAdd::eRegexSummary : CommandObjectTypeSummaryAdd::eRegularSummary),
+ options->m_category,
+ &error);
+ if (error.Fail())
+ {
+ out_stream->Printf ("%s", error.AsCString());
+ out_stream->Flush();
+ return;
+ }
+ }
+
+ if (options->m_name)
+ {
+ CommandObjectTypeSummaryAdd::AddSummary (options->m_name,
+ script_format,
+ CommandObjectTypeSummaryAdd::eNamedSummary,
+ options->m_category,
+ &error);
+ if (error.Fail())
+ {
+ CommandObjectTypeSummaryAdd::AddSummary (options->m_name,
+ script_format,
+ CommandObjectTypeSummaryAdd::eNamedSummary,
+ options->m_category,
+ &error);
+ if (error.Fail())
+ {
+ out_stream->Printf ("%s", error.AsCString());
+ out_stream->Flush();
+ return;
+ }
+ }
+ else
+ {
+ out_stream->Printf ("%s", error.AsCString());
+ out_stream->Flush();
+ return;
+ }
+ }
+ else
+ {
+ if (error.AsCString())
+ {
+ out_stream->PutCString (error.AsCString());
+ out_stream->Flush();
+ }
+ return;
+ }
+ }
+};
+
+#endif // #ifndef LLDB_DISABLE_PYTHON
+
+Error
+CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg)
+{
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+ bool success;
+
+ switch (short_option)
+ {
+ case 'C':
+ m_flags.SetCascades(Args::StringToBoolean(option_arg, true, &success));
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for cascade: %s", option_arg);
+ break;
+ case 'e':
+ m_flags.SetDontShowChildren(false);
+ break;
+ case 'v':
+ m_flags.SetDontShowValue(true);
+ break;
+ case 'c':
+ m_flags.SetShowMembersOneLiner(true);
+ break;
+ case 's':
+ m_format_string = std::string(option_arg);
+ break;
+ case 'p':
+ m_flags.SetSkipPointers(true);
+ break;
+ case 'r':
+ m_flags.SetSkipReferences(true);
+ break;
+ case 'x':
+ m_regex = true;
+ break;
+ case 'n':
+ m_name.SetCString(option_arg);
+ break;
+ case 'o':
+ m_python_script = std::string(option_arg);
+ m_is_add_script = true;
+ break;
+ case 'F':
+ m_python_function = std::string(option_arg);
+ m_is_add_script = true;
+ break;
+ case 'P':
+ m_is_add_script = true;
+ break;
+ case 'w':
+ m_category = std::string(option_arg);
+ break;
+ case 'O':
+ m_flags.SetHideItemNames(true);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectTypeSummaryAdd::CommandOptions::OptionParsingStarting ()
+{
+ m_flags.Clear().SetCascades().SetDontShowChildren().SetDontShowValue(false);
+ m_flags.SetShowMembersOneLiner(false).SetSkipPointers(false).SetSkipReferences(false).SetHideItemNames(false);
+
+ m_regex = false;
+ m_name.Clear();
+ m_python_script = "";
+ m_python_function = "";
+ m_format_string = "";
+ m_is_add_script = false;
+ m_category = "default";
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+void
+CommandObjectTypeSummaryAdd::CollectPythonScript (ScriptAddOptions *options,
+ CommandReturnObject &result)
+{
+ InputReaderSP reader_sp (new TypeScriptAddInputReader(m_interpreter.GetDebugger()));
+ if (reader_sp && options)
+ {
+
+ InputReaderEZ::InitializationParameters ipr;
+
+ Error err (reader_sp->Initialize (ipr.SetBaton(options).SetPrompt(" ")));
+ if (err.Success())
+ {
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+}
+
+bool
+CommandObjectTypeSummaryAdd::Execute_ScriptSummary (Args& command, CommandReturnObject &result)
+{
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1 && !m_options.m_name)
+ {
+ result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ TypeSummaryImplSP script_format;
+
+ if (!m_options.m_python_function.empty()) // we have a Python function ready to use
+ {
+ const char *funct_name = m_options.m_python_function.c_str();
+ if (!funct_name || !funct_name[0])
+ {
+ result.AppendError ("function name empty.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ std::string code = (" " + m_options.m_python_function + "(valobj,internal_dict)");
+
+ script_format.reset(new ScriptSummaryFormat(m_options.m_flags,
+ funct_name,
+ code.c_str()));
+
+ ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
+
+ if (interpreter && interpreter->CheckObjectExists(funct_name) == false)
+ result.AppendWarningWithFormat("The provided function \"%s\" does not exist - "
+ "please define it before attempting to use this summary.\n",
+ funct_name);
+ }
+ else if (!m_options.m_python_script.empty()) // we have a quick 1-line script, just use it
+ {
+ ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
+ if (!interpreter)
+ {
+ result.AppendError ("script interpreter missing - unable to generate function wrapper.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ StringList funct_sl;
+ funct_sl << m_options.m_python_script.c_str();
+ std::string funct_name_str;
+ if (!interpreter->GenerateTypeScriptFunction (funct_sl,
+ funct_name_str))
+ {
+ result.AppendError ("unable to generate function wrapper.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ if (funct_name_str.empty())
+ {
+ result.AppendError ("script interpreter failed to generate a valid function name.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ std::string code = " " + m_options.m_python_script;
+
+ script_format.reset(new ScriptSummaryFormat(m_options.m_flags,
+ funct_name_str.c_str(),
+ code.c_str()));
+ }
+ else // use an InputReader to grab Python code from the user
+ {
+ ScriptAddOptions *options = new ScriptAddOptions(m_options.m_flags,
+ m_options.m_regex,
+ m_options.m_name,
+ m_options.m_category);
+
+ for (size_t i = 0; i < argc; i++)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ if (typeA && *typeA)
+ options->m_target_types << typeA;
+ else
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ CollectPythonScript(options,result);
+ return result.Succeeded();
+ }
+
+ // if I am here, script_format must point to something good, so I can add that
+ // as a script summary to all interested parties
+
+ Error error;
+
+ for (size_t i = 0; i < command.GetArgumentCount(); i++)
+ {
+ const char *type_name = command.GetArgumentAtIndex(i);
+ CommandObjectTypeSummaryAdd::AddSummary(ConstString(type_name),
+ script_format,
+ (m_options.m_regex ? eRegexSummary : eRegularSummary),
+ m_options.m_category,
+ &error);
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ if (m_options.m_name)
+ {
+ AddSummary(m_options.m_name, script_format, eNamedSummary, m_options.m_category, &error);
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString());
+ result.AppendError("added to types, but not given a name");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ return result.Succeeded();
+}
+
+#endif
+
+
+bool
+CommandObjectTypeSummaryAdd::Execute_StringSummary (Args& command, CommandReturnObject &result)
+{
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1 && !m_options.m_name)
+ {
+ result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (!m_options.m_flags.GetShowMembersOneLiner() && m_options.m_format_string.empty())
+ {
+ result.AppendError("empty summary strings not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const char* format_cstr = (m_options.m_flags.GetShowMembersOneLiner() ? "" : m_options.m_format_string.c_str());
+
+ // ${var%S} is an endless recursion, prevent it
+ if (strcmp(format_cstr, "${var%S}") == 0)
+ {
+ result.AppendError("recursive summary not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ Error error;
+
+ lldb::TypeSummaryImplSP entry(new StringSummaryFormat(m_options.m_flags,
+ format_cstr));
+
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ // now I have a valid format, let's add it to every type
+
+ for (size_t i = 0; i < argc; i++)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ if (!typeA || typeA[0] == '\0')
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ ConstString typeCS(typeA);
+
+ AddSummary(typeCS,
+ entry,
+ (m_options.m_regex ? eRegexSummary : eRegularSummary),
+ m_options.m_category,
+ &error);
+
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ if (m_options.m_name)
+ {
+ AddSummary(m_options.m_name, entry, eNamedSummary, m_options.m_category, &error);
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString());
+ result.AppendError("added to types, but not given a name");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+}
+
+CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type summary add",
+ "Add a new summary style for a type.",
+ NULL),
+ m_options (interpreter)
+{
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlus;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ SetHelpLong(
+ "Some examples of using this command.\n"
+ "We use as reference the following snippet of code:\n"
+ "struct JustADemo\n"
+ "{\n"
+ "int* ptr;\n"
+ "float value;\n"
+ "JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {}\n"
+ "};\n"
+ "JustADemo object(42,3.14);\n"
+ "struct AnotherDemo : public JustADemo\n"
+ "{\n"
+ "uint8_t byte;\n"
+ "AnotherDemo(uint8_t b = 'E', int p = 1, float v = 0.1) : JustADemo(p,v), byte(b) {}\n"
+ "};\n"
+ "AnotherDemo *another_object = new AnotherDemo('E',42,3.14);\n"
+ "\n"
+ "type summary add --summary-string \"the answer is ${*var.ptr}\" JustADemo\n"
+ "when typing frame variable object you will get \"the answer is 42\"\n"
+ "type summary add --summary-string \"the answer is ${*var.ptr}, and the question is ${var.value}\" JustADemo\n"
+ "when typing frame variable object you will get \"the answer is 42 and the question is 3.14\"\n"
+ "\n"
+ "Alternatively, you could also say\n"
+ "type summary add --summary-string \"${var%V} -> ${*var}\" \"int *\"\n"
+ "and replace the above summary string with\n"
+ "type summary add --summary-string \"the answer is ${var.ptr}, and the question is ${var.value}\" JustADemo\n"
+ "to obtain a similar result\n"
+ "\n"
+ "To add a summary valid for both JustADemo and AnotherDemo you can use the scoping operator, as in:\n"
+ "type summary add --summary-string \"${var.ptr}, ${var.value},{${var.byte}}\" JustADemo -C yes\n"
+ "\n"
+ "This will be used for both variables of type JustADemo and AnotherDemo. To prevent this, change the -C to read -C no\n"
+ "If you do not want pointers to be shown using that summary, you can use the -p option, as in:\n"
+ "type summary add --summary-string \"${var.ptr}, ${var.value},{${var.byte}}\" JustADemo -C yes -p\n"
+ "A similar option -r exists for references.\n"
+ "\n"
+ "If you simply want a one-line summary of the content of your variable, without typing an explicit string to that effect\n"
+ "you can use the -c option, without giving any summary string:\n"
+ "type summary add -c JustADemo\n"
+ "frame variable object\n"
+ "the output being similar to (ptr=0xsomeaddress, value=3.14)\n"
+ "\n"
+ "If you want to display some summary text, but also expand the structure of your object, you can add the -e option, as in:\n"
+ "type summary add -e --summary-string \"*ptr = ${*var.ptr}\" JustADemo\n"
+ "Here the value of the int* is displayed, followed by the standard LLDB sequence of children objects, one per line.\n"
+ "to get an output like:\n"
+ "\n"
+ "*ptr = 42 {\n"
+ " ptr = 0xsomeaddress\n"
+ " value = 3.14\n"
+ "}\n"
+ "\n"
+ "You can also add Python summaries, in which case you will use lldb public API to gather information from your variables"
+ "and elaborate them to a meaningful summary inside a script written in Python. The variable object will be passed to your"
+ "script as an SBValue object. The following example might help you when starting to use the Python summaries feature:\n"
+ "type summary add JustADemo -o \"value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();\"\n"
+ "If you prefer to type your scripts on multiple lines, you will use the -P option and then type your script, ending it with "
+ "the word DONE on a line by itself to mark you're finished editing your code:\n"
+ "(lldb)type summary add JustADemo -P\n"
+ " value = valobj.GetChildMemberWithName('value');\n"
+ " return 'My value is ' + value.GetValue();\n"
+ "DONE\n"
+ "(lldb) <-- type further LLDB commands here\n"
+ );
+}
+
+bool
+CommandObjectTypeSummaryAdd::DoExecute (Args& command, CommandReturnObject &result)
+{
+ if (m_options.m_is_add_script)
+ {
+#ifndef LLDB_DISABLE_PYTHON
+ return Execute_ScriptSummary(command, result);
+#else
+ result.AppendError ("python is disabled");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+#endif
+ }
+
+ return Execute_StringSummary(command, result);
+}
+
+bool
+CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name,
+ TypeSummaryImplSP entry,
+ SummaryFormatType type,
+ std::string category_name,
+ Error* error)
+{
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()), category);
+
+ if (type == eRegularSummary)
+ {
+ std::string type_name_str(type_name.GetCString());
+ if (type_name_str.compare(type_name_str.length() - 2, 2, "[]") == 0)
+ {
+ type_name_str.resize(type_name_str.length()-2);
+ if (type_name_str.back() != ' ')
+ type_name_str.append(" \\[[0-9]+\\]");
+ else
+ type_name_str.append("\\[[0-9]+\\]");
+ type_name.SetCString(type_name_str.c_str());
+ type = eRegexSummary;
+ }
+ }
+
+ if (type == eRegexSummary)
+ {
+ RegularExpressionSP typeRX(new RegularExpression());
+ if (!typeRX->Compile(type_name.GetCString()))
+ {
+ if (error)
+ error->SetErrorString("regex format error (maybe this is not really a regex?)");
+ return false;
+ }
+
+ category->GetRegexSummaryNavigator()->Delete(type_name);
+ category->GetRegexSummaryNavigator()->Add(typeRX, entry);
+
+ return true;
+ }
+ else if (type == eNamedSummary)
+ {
+ // system named summaries do not exist (yet?)
+ DataVisualization::NamedSummaryFormats::Add(type_name,entry);
+ return true;
+ }
+ else
+ {
+ category->GetSummaryNavigator()->Add(type_name, entry);
+ return true;
+ }
+}
+
+OptionDefinition
+CommandObjectTypeSummaryAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
+ { LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
+ { LLDB_OPT_SET_ALL, false, "no-value", 'v', no_argument, NULL, 0, eArgTypeNone, "Don't show the value, just show the summary, for this type."},
+ { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "skip-references", 'r', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "regex", 'x', no_argument, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."},
+ { LLDB_OPT_SET_1 , true, "inline-children", 'c', no_argument, NULL, 0, eArgTypeNone, "If true, inline all child values into summary string."},
+ { LLDB_OPT_SET_1 , false, "omit-names", 'O', no_argument, NULL, 0, eArgTypeNone, "If true, omit value names in the summary display."},
+ { LLDB_OPT_SET_2 , true, "summary-string", 's', required_argument, NULL, 0, eArgTypeSummaryString, "Summary string used to display text and object contents."},
+ { LLDB_OPT_SET_3, false, "python-script", 'o', required_argument, NULL, 0, eArgTypePythonScript, "Give a one-liner Python script as part of the command."},
+ { LLDB_OPT_SET_3, false, "python-function", 'F', required_argument, NULL, 0, eArgTypePythonFunction, "Give the name of a Python function to use for this type."},
+ { LLDB_OPT_SET_3, false, "input-python", 'P', no_argument, NULL, 0, eArgTypeNone, "Input Python code to use for this type manually."},
+ { LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "expand", 'e', no_argument, NULL, 0, eArgTypeNone, "Expand aggregate data types to show children on separate lines."},
+ { LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "name", 'n', required_argument, NULL, 0, eArgTypeName, "A name for this summary string."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSummaryDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeSummaryDelete : public CommandObjectParsed
+{
+private:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_delete_all = true;
+ break;
+ case 'w':
+ m_category = std::string(option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_delete_all = false;
+ m_category = "default";
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_delete_all;
+ std::string m_category;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ static bool
+ PerCategoryCallback(void* param,
+ const lldb::TypeCategoryImplSP& category_sp)
+ {
+ ConstString *name = (ConstString*)param;
+ category_sp->Delete(*name, eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary);
+ return true;
+ }
+
+public:
+ CommandObjectTypeSummaryDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type summary delete",
+ "Delete an existing summary style for a type.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlain;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ }
+
+ ~CommandObjectTypeSummaryDelete ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const char* typeA = command.GetArgumentAtIndex(0);
+ ConstString typeCS(typeA);
+
+ if (!typeCS)
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_delete_all)
+ {
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback, &typeCS);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category);
+
+ bool delete_category = category->Delete(typeCS,
+ eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary);
+ bool delete_named = DataVisualization::NamedSummaryFormats::Delete(typeCS);
+
+ if (delete_category || delete_named)
+ {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no custom summary for %s.\n", typeA);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ }
+};
+
+OptionDefinition
+CommandObjectTypeSummaryDelete::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "all", 'a', no_argument, NULL, 0, eArgTypeNone, "Delete from every category."},
+ { LLDB_OPT_SET_2, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Delete from given category."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+class CommandObjectTypeSummaryClear : public CommandObjectParsed
+{
+private:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_delete_all = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_delete_all = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_delete_all;
+ bool m_delete_named;
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ static bool
+ PerCategoryCallback(void* param,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+ cate->GetSummaryNavigator()->Clear();
+ cate->GetRegexSummaryNavigator()->Clear();
+ return true;
+
+ }
+
+public:
+ CommandObjectTypeSummaryClear (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type summary clear",
+ "Delete all existing summary styles.",
+ NULL),
+ m_options(interpreter)
+ {
+ }
+
+ ~CommandObjectTypeSummaryClear ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ if (m_options.m_delete_all)
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback, NULL);
+
+ else
+ {
+ lldb::TypeCategoryImplSP category;
+ if (command.GetArgumentCount() > 0)
+ {
+ const char* cat_name = command.GetArgumentAtIndex(0);
+ ConstString cat_nameCS(cat_name);
+ DataVisualization::Categories::GetCategory(cat_nameCS, category);
+ }
+ else
+ DataVisualization::Categories::GetCategory(ConstString(NULL), category);
+ category->Clear(eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary);
+ }
+
+ DataVisualization::NamedSummaryFormats::Clear();
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+OptionDefinition
+CommandObjectTypeSummaryClear::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "all", 'a', no_argument, NULL, 0, eArgTypeNone, "Clear every category."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSummaryList
+//-------------------------------------------------------------------------
+
+bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, ConstString type, const StringSummaryFormat::SharedPointer& entry);
+bool CommandObjectTypeRXSummaryList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const StringSummaryFormat::SharedPointer& entry);
+
+class CommandObjectTypeSummaryList;
+
+struct CommandObjectTypeSummaryList_LoopCallbackParam {
+ CommandObjectTypeSummaryList* self;
+ CommandReturnObject* result;
+ RegularExpression* regex;
+ RegularExpression* cate_regex;
+ CommandObjectTypeSummaryList_LoopCallbackParam(CommandObjectTypeSummaryList* S, CommandReturnObject* R,
+ RegularExpression* X = NULL,
+ RegularExpression* CX = NULL) : self(S), result(R), regex(X), cate_regex(CX) {}
+};
+
+class CommandObjectTypeSummaryList : public CommandObjectParsed
+{
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'w':
+ m_category_regex = std::string(option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_category_regex = "";
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ std::string m_category_regex;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+public:
+ CommandObjectTypeSummaryList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type summary list",
+ "Show a list of current summary styles.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatOptional;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+ }
+
+ ~CommandObjectTypeSummaryList ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ CommandObjectTypeSummaryList_LoopCallbackParam *param;
+ RegularExpression* cate_regex =
+ m_options.m_category_regex.empty() ? NULL :
+ new RegularExpression(m_options.m_category_regex.c_str());
+
+ if (argc == 1)
+ {
+ RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
+ regex->Compile(command.GetArgumentAtIndex(0));
+ param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result,regex,cate_regex);
+ }
+ else
+ param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result,NULL,cate_regex);
+
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback,param);
+
+ if (DataVisualization::NamedSummaryFormats::GetCount() > 0)
+ {
+ result.GetOutputStream().Printf("Named summaries:\n");
+ if (argc == 1)
+ {
+ RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
+ regex->Compile(command.GetArgumentAtIndex(0));
+ param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result,regex);
+ }
+ else
+ param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result);
+ DataVisualization::NamedSummaryFormats::LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param);
+ delete param;
+ }
+
+ if (cate_regex)
+ delete cate_regex;
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+private:
+
+ static bool
+ PerCategoryCallback(void* param_vp,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+
+ CommandObjectTypeSummaryList_LoopCallbackParam* param =
+ (CommandObjectTypeSummaryList_LoopCallbackParam*)param_vp;
+ CommandReturnObject* result = param->result;
+
+ const char* cate_name = cate->GetName();
+
+ // if the category is disabled or empty and there is no regex, just skip it
+ if ((cate->IsEnabled() == false || cate->GetCount(eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary) == 0) && param->cate_regex == NULL)
+ return true;
+
+ // if we have a regex and this category does not match it, just skip it
+ if(param->cate_regex != NULL && strcmp(cate_name,param->cate_regex->GetText()) != 0 && param->cate_regex->Execute(cate_name) == false)
+ return true;
+
+ result->GetOutputStream().Printf("-----------------------\nCategory: %s (%s)\n-----------------------\n",
+ cate_name,
+ (cate->IsEnabled() ? "enabled" : "disabled"));
+
+ cate->GetSummaryNavigator()->LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param_vp);
+
+ if (cate->GetRegexSummaryNavigator()->GetCount() > 0)
+ {
+ result->GetOutputStream().Printf("Regex-based summaries (slower):\n");
+ cate->GetRegexSummaryNavigator()->LoopThrough(CommandObjectTypeRXSummaryList_LoopCallback, param_vp);
+ }
+ return true;
+ }
+
+
+ bool
+ LoopCallback (const char* type,
+ const lldb::TypeSummaryImplSP& entry,
+ RegularExpression* regex,
+ CommandReturnObject *result)
+ {
+ if (regex == NULL || strcmp(type,regex->GetText()) == 0 || regex->Execute(type))
+ result->GetOutputStream().Printf ("%s: %s\n", type, entry->GetDescription().c_str());
+ return true;
+ }
+
+ friend bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, ConstString type, const lldb::TypeSummaryImplSP& entry);
+ friend bool CommandObjectTypeRXSummaryList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const lldb::TypeSummaryImplSP& entry);
+};
+
+bool
+CommandObjectTypeSummaryList_LoopCallback (
+ void* pt2self,
+ ConstString type,
+ const lldb::TypeSummaryImplSP& entry)
+{
+ CommandObjectTypeSummaryList_LoopCallbackParam* param = (CommandObjectTypeSummaryList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(type.AsCString(), entry, param->regex, param->result);
+}
+
+bool
+CommandObjectTypeRXSummaryList_LoopCallback (
+ void* pt2self,
+ lldb::RegularExpressionSP regex,
+ const lldb::TypeSummaryImplSP& entry)
+{
+ CommandObjectTypeSummaryList_LoopCallbackParam* param = (CommandObjectTypeSummaryList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(regex->GetText(), entry, param->regex, param->result);
+}
+
+OptionDefinition
+CommandObjectTypeSummaryList::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "category-regex", 'w', required_argument, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeCategoryEnable
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeCategoryEnable : public CommandObjectParsed
+{
+public:
+ CommandObjectTypeCategoryEnable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type category enable",
+ "Enable a category as a source of formatters.",
+ NULL)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlus;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ }
+
+ ~CommandObjectTypeCategoryEnable ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 or more args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (argc == 1 && strcmp(command.GetArgumentAtIndex(0),"*") == 0)
+ {
+ // we want to make sure to enable "system" last and "default" first
+ DataVisualization::Categories::Enable(ConstString("default"), TypeCategoryMap::First);
+ uint32_t num_categories = DataVisualization::Categories::GetCount();
+ for (uint32_t i = 0; i < num_categories; i++)
+ {
+ lldb::TypeCategoryImplSP category_sp = DataVisualization::Categories::GetCategoryAtIndex(i);
+ if (category_sp)
+ {
+ if ( ::strcmp(category_sp->GetName(), "system") == 0 ||
+ ::strcmp(category_sp->GetName(), "default") == 0 )
+ continue;
+ else
+ DataVisualization::Categories::Enable(category_sp, TypeCategoryMap::Default);
+ }
+ }
+ DataVisualization::Categories::Enable(ConstString("system"), TypeCategoryMap::Last);
+ }
+ else
+ {
+ for (int i = argc - 1; i >= 0; i--)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ ConstString typeCS(typeA);
+
+ if (!typeCS)
+ {
+ result.AppendError("empty category name not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ DataVisualization::Categories::Enable(typeCS);
+ lldb::TypeCategoryImplSP cate;
+ if (DataVisualization::Categories::GetCategory(typeCS, cate) && cate.get())
+ {
+ if (cate->GetCount() == 0)
+ {
+ result.AppendWarning("empty category enabled (typo?)");
+ }
+ }
+ }
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeCategoryDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeCategoryDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectTypeCategoryDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type category delete",
+ "Delete a category and all associated formatters.",
+ NULL)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlus;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ }
+
+ ~CommandObjectTypeCategoryDelete ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 or more arg.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ bool success = true;
+
+ // the order is not relevant here
+ for (int i = argc - 1; i >= 0; i--)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ ConstString typeCS(typeA);
+
+ if (!typeCS)
+ {
+ result.AppendError("empty category name not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ if (!DataVisualization::Categories::Delete(typeCS))
+ success = false; // keep deleting even if we hit an error
+ }
+ if (success)
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+ else
+ {
+ result.AppendError("cannot delete one or more categories\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeCategoryDisable
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeCategoryDisable : public CommandObjectParsed
+{
+public:
+ CommandObjectTypeCategoryDisable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type category disable",
+ "Disable a category as a source of formatters.",
+ NULL)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlus;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ }
+
+ ~CommandObjectTypeCategoryDisable ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 or more args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (argc == 1 && strcmp(command.GetArgumentAtIndex(0),"*") == 0)
+ {
+ uint32_t num_categories = DataVisualization::Categories::GetCount();
+ for (uint32_t i = 0; i < num_categories; i++)
+ {
+ lldb::TypeCategoryImplSP category_sp = DataVisualization::Categories::GetCategoryAtIndex(i);
+ // no need to check if the category is enabled - disabling a disabled category has no effect
+ if (category_sp)
+ DataVisualization::Categories::Disable(category_sp);
+ }
+ }
+ else
+ {
+ // the order is not relevant here
+ for (int i = argc - 1; i >= 0; i--)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ ConstString typeCS(typeA);
+
+ if (!typeCS)
+ {
+ result.AppendError("empty category name not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ DataVisualization::Categories::Disable(typeCS);
+ }
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeCategoryList
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeCategoryList : public CommandObjectParsed
+{
+private:
+
+ struct CommandObjectTypeCategoryList_CallbackParam
+ {
+ CommandReturnObject* result;
+ RegularExpression* regex;
+
+ CommandObjectTypeCategoryList_CallbackParam(CommandReturnObject* res,
+ RegularExpression* rex = NULL) :
+ result(res),
+ regex(rex)
+ {
+ }
+
+ };
+
+ static bool
+ PerCategoryCallback(void* param_vp,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+ CommandObjectTypeCategoryList_CallbackParam* param =
+ (CommandObjectTypeCategoryList_CallbackParam*)param_vp;
+ CommandReturnObject* result = param->result;
+ RegularExpression* regex = param->regex;
+
+ const char* cate_name = cate->GetName();
+
+ if (regex == NULL || strcmp(cate_name, regex->GetText()) == 0 || regex->Execute(cate_name))
+ result->GetOutputStream().Printf("Category %s is%s enabled\n",
+ cate_name,
+ (cate->IsEnabled() ? "" : " not"));
+ return true;
+ }
+public:
+ CommandObjectTypeCategoryList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type category list",
+ "Provide a list of all existing categories.",
+ NULL)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatOptional;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+ }
+
+ ~CommandObjectTypeCategoryList ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ RegularExpression* regex = NULL;
+
+ if (argc == 0)
+ ;
+ else if (argc == 1)
+ regex = new RegularExpression(command.GetArgumentAtIndex(0));
+ else
+ {
+ result.AppendErrorWithFormat ("%s takes 0 or one arg.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ CommandObjectTypeCategoryList_CallbackParam param(&result,
+ regex);
+
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback, &param);
+
+ if (regex)
+ delete regex;
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeFilterList
+//-------------------------------------------------------------------------
+
+bool CommandObjectTypeFilterList_LoopCallback(void* pt2self, ConstString type, const SyntheticChildren::SharedPointer& entry);
+bool CommandObjectTypeFilterRXList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SyntheticChildren::SharedPointer& entry);
+
+class CommandObjectTypeFilterList;
+
+struct CommandObjectTypeFilterList_LoopCallbackParam {
+ CommandObjectTypeFilterList* self;
+ CommandReturnObject* result;
+ RegularExpression* regex;
+ RegularExpression* cate_regex;
+ CommandObjectTypeFilterList_LoopCallbackParam(CommandObjectTypeFilterList* S, CommandReturnObject* R,
+ RegularExpression* X = NULL,
+ RegularExpression* CX = NULL) : self(S), result(R), regex(X), cate_regex(CX) {}
+};
+
+class CommandObjectTypeFilterList : public CommandObjectParsed
+{
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'w':
+ m_category_regex = std::string(option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_category_regex = "";
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ std::string m_category_regex;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+public:
+ CommandObjectTypeFilterList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type filter list",
+ "Show a list of current filters.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatOptional;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+ }
+
+ ~CommandObjectTypeFilterList ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ CommandObjectTypeFilterList_LoopCallbackParam *param;
+ RegularExpression* cate_regex =
+ m_options.m_category_regex.empty() ? NULL :
+ new RegularExpression(m_options.m_category_regex.c_str());
+
+ if (argc == 1)
+ {
+ RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
+ regex->Compile(command.GetArgumentAtIndex(0));
+ param = new CommandObjectTypeFilterList_LoopCallbackParam(this,&result,regex,cate_regex);
+ }
+ else
+ param = new CommandObjectTypeFilterList_LoopCallbackParam(this,&result,NULL,cate_regex);
+
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback,param);
+
+ if (cate_regex)
+ delete cate_regex;
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+private:
+
+ static bool
+ PerCategoryCallback(void* param_vp,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+
+ const char* cate_name = cate->GetName();
+
+ CommandObjectTypeFilterList_LoopCallbackParam* param =
+ (CommandObjectTypeFilterList_LoopCallbackParam*)param_vp;
+ CommandReturnObject* result = param->result;
+
+ // if the category is disabled or empty and there is no regex, just skip it
+ if ((cate->IsEnabled() == false || cate->GetCount(eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter) == 0) && param->cate_regex == NULL)
+ return true;
+
+ // if we have a regex and this category does not match it, just skip it
+ if(param->cate_regex != NULL && strcmp(cate_name,param->cate_regex->GetText()) != 0 && param->cate_regex->Execute(cate_name) == false)
+ return true;
+
+ result->GetOutputStream().Printf("-----------------------\nCategory: %s (%s)\n-----------------------\n",
+ cate_name,
+ (cate->IsEnabled() ? "enabled" : "disabled"));
+
+ cate->GetFilterNavigator()->LoopThrough(CommandObjectTypeFilterList_LoopCallback, param_vp);
+
+ if (cate->GetRegexFilterNavigator()->GetCount() > 0)
+ {
+ result->GetOutputStream().Printf("Regex-based filters (slower):\n");
+ cate->GetRegexFilterNavigator()->LoopThrough(CommandObjectTypeFilterRXList_LoopCallback, param_vp);
+ }
+
+ return true;
+ }
+
+ bool
+ LoopCallback (const char* type,
+ const SyntheticChildren::SharedPointer& entry,
+ RegularExpression* regex,
+ CommandReturnObject *result)
+ {
+ if (regex == NULL || regex->Execute(type))
+ result->GetOutputStream().Printf ("%s: %s\n", type, entry->GetDescription().c_str());
+ return true;
+ }
+
+ friend bool CommandObjectTypeFilterList_LoopCallback(void* pt2self, ConstString type, const SyntheticChildren::SharedPointer& entry);
+ friend bool CommandObjectTypeFilterRXList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SyntheticChildren::SharedPointer& entry);
+};
+
+bool
+CommandObjectTypeFilterList_LoopCallback (void* pt2self,
+ ConstString type,
+ const SyntheticChildren::SharedPointer& entry)
+{
+ CommandObjectTypeFilterList_LoopCallbackParam* param = (CommandObjectTypeFilterList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(type.AsCString(), entry, param->regex, param->result);
+}
+
+bool
+CommandObjectTypeFilterRXList_LoopCallback (void* pt2self,
+ lldb::RegularExpressionSP regex,
+ const SyntheticChildren::SharedPointer& entry)
+{
+ CommandObjectTypeFilterList_LoopCallbackParam* param = (CommandObjectTypeFilterList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(regex->GetText(), entry, param->regex, param->result);
+}
+
+
+OptionDefinition
+CommandObjectTypeFilterList::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "category-regex", 'w', required_argument, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#ifndef LLDB_DISABLE_PYTHON
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSynthList
+//-------------------------------------------------------------------------
+
+bool CommandObjectTypeSynthList_LoopCallback(void* pt2self, ConstString type, const SyntheticChildren::SharedPointer& entry);
+bool CommandObjectTypeSynthRXList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SyntheticChildren::SharedPointer& entry);
+
+class CommandObjectTypeSynthList;
+
+struct CommandObjectTypeSynthList_LoopCallbackParam {
+ CommandObjectTypeSynthList* self;
+ CommandReturnObject* result;
+ RegularExpression* regex;
+ RegularExpression* cate_regex;
+ CommandObjectTypeSynthList_LoopCallbackParam(CommandObjectTypeSynthList* S, CommandReturnObject* R,
+ RegularExpression* X = NULL,
+ RegularExpression* CX = NULL) : self(S), result(R), regex(X), cate_regex(CX) {}
+};
+
+class CommandObjectTypeSynthList : public CommandObjectParsed
+{
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'w':
+ m_category_regex = std::string(option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_category_regex = "";
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ std::string m_category_regex;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+public:
+ CommandObjectTypeSynthList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type synthetic list",
+ "Show a list of current synthetic providers.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatOptional;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+ }
+
+ ~CommandObjectTypeSynthList ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ CommandObjectTypeSynthList_LoopCallbackParam *param;
+ RegularExpression* cate_regex =
+ m_options.m_category_regex.empty() ? NULL :
+ new RegularExpression(m_options.m_category_regex.c_str());
+
+ if (argc == 1)
+ {
+ RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
+ regex->Compile(command.GetArgumentAtIndex(0));
+ param = new CommandObjectTypeSynthList_LoopCallbackParam(this,&result,regex,cate_regex);
+ }
+ else
+ param = new CommandObjectTypeSynthList_LoopCallbackParam(this,&result,NULL,cate_regex);
+
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback,param);
+
+ if (cate_regex)
+ delete cate_regex;
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+private:
+
+ static bool
+ PerCategoryCallback(void* param_vp,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+
+ CommandObjectTypeSynthList_LoopCallbackParam* param =
+ (CommandObjectTypeSynthList_LoopCallbackParam*)param_vp;
+ CommandReturnObject* result = param->result;
+
+ const char* cate_name = cate->GetName();
+
+ // if the category is disabled or empty and there is no regex, just skip it
+ if ((cate->IsEnabled() == false || cate->GetCount(eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth) == 0) && param->cate_regex == NULL)
+ return true;
+
+ // if we have a regex and this category does not match it, just skip it
+ if(param->cate_regex != NULL && strcmp(cate_name,param->cate_regex->GetText()) != 0 && param->cate_regex->Execute(cate_name) == false)
+ return true;
+
+ result->GetOutputStream().Printf("-----------------------\nCategory: %s (%s)\n-----------------------\n",
+ cate_name,
+ (cate->IsEnabled() ? "enabled" : "disabled"));
+
+ cate->GetSyntheticNavigator()->LoopThrough(CommandObjectTypeSynthList_LoopCallback, param_vp);
+
+ if (cate->GetRegexSyntheticNavigator()->GetCount() > 0)
+ {
+ result->GetOutputStream().Printf("Regex-based synthetic providers (slower):\n");
+ cate->GetRegexSyntheticNavigator()->LoopThrough(CommandObjectTypeSynthRXList_LoopCallback, param_vp);
+ }
+
+ return true;
+ }
+
+ bool
+ LoopCallback (const char* type,
+ const SyntheticChildren::SharedPointer& entry,
+ RegularExpression* regex,
+ CommandReturnObject *result)
+ {
+ if (regex == NULL || regex->Execute(type))
+ result->GetOutputStream().Printf ("%s: %s\n", type, entry->GetDescription().c_str());
+ return true;
+ }
+
+ friend bool CommandObjectTypeSynthList_LoopCallback(void* pt2self, ConstString type, const SyntheticChildren::SharedPointer& entry);
+ friend bool CommandObjectTypeSynthRXList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SyntheticChildren::SharedPointer& entry);
+};
+
+bool
+CommandObjectTypeSynthList_LoopCallback (void* pt2self,
+ ConstString type,
+ const SyntheticChildren::SharedPointer& entry)
+{
+ CommandObjectTypeSynthList_LoopCallbackParam* param = (CommandObjectTypeSynthList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(type.AsCString(), entry, param->regex, param->result);
+}
+
+bool
+CommandObjectTypeSynthRXList_LoopCallback (void* pt2self,
+ lldb::RegularExpressionSP regex,
+ const SyntheticChildren::SharedPointer& entry)
+{
+ CommandObjectTypeSynthList_LoopCallbackParam* param = (CommandObjectTypeSynthList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(regex->GetText(), entry, param->regex, param->result);
+}
+
+
+OptionDefinition
+CommandObjectTypeSynthList::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "category-regex", 'w', required_argument, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#endif // #ifndef LLDB_DISABLE_PYTHON
+//-------------------------------------------------------------------------
+// CommandObjectTypeFilterDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeFilterDelete : public CommandObjectParsed
+{
+private:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_delete_all = true;
+ break;
+ case 'w':
+ m_category = std::string(option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_delete_all = false;
+ m_category = "default";
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_delete_all;
+ std::string m_category;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ static bool
+ PerCategoryCallback(void* param,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+ ConstString *name = (ConstString*)param;
+ return cate->Delete(*name, eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter);
+ }
+
+public:
+ CommandObjectTypeFilterDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type filter delete",
+ "Delete an existing filter for a type.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlain;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ }
+
+ ~CommandObjectTypeFilterDelete ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const char* typeA = command.GetArgumentAtIndex(0);
+ ConstString typeCS(typeA);
+
+ if (!typeCS)
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_delete_all)
+ {
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback, (void*)&typeCS);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category);
+
+ bool delete_category = category->GetFilterNavigator()->Delete(typeCS);
+ delete_category = category->GetRegexFilterNavigator()->Delete(typeCS) || delete_category;
+
+ if (delete_category)
+ {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no custom synthetic provider for %s.\n", typeA);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ }
+};
+
+OptionDefinition
+CommandObjectTypeFilterDelete::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "all", 'a', no_argument, NULL, 0, eArgTypeNone, "Delete from every category."},
+ { LLDB_OPT_SET_2, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Delete from given category."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#ifndef LLDB_DISABLE_PYTHON
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSynthDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeSynthDelete : public CommandObjectParsed
+{
+private:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_delete_all = true;
+ break;
+ case 'w':
+ m_category = std::string(option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_delete_all = false;
+ m_category = "default";
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_delete_all;
+ std::string m_category;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ static bool
+ PerCategoryCallback(void* param,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+ ConstString* name = (ConstString*)param;
+ return cate->Delete(*name, eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth);
+ }
+
+public:
+ CommandObjectTypeSynthDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type synthetic delete",
+ "Delete an existing synthetic provider for a type.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlain;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ }
+
+ ~CommandObjectTypeSynthDelete ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const char* typeA = command.GetArgumentAtIndex(0);
+ ConstString typeCS(typeA);
+
+ if (!typeCS)
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_delete_all)
+ {
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback, (void*)&typeCS);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category);
+
+ bool delete_category = category->GetSyntheticNavigator()->Delete(typeCS);
+ delete_category = category->GetRegexSyntheticNavigator()->Delete(typeCS) || delete_category;
+
+ if (delete_category)
+ {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no custom synthetic provider for %s.\n", typeA);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ }
+};
+
+OptionDefinition
+CommandObjectTypeSynthDelete::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "all", 'a', no_argument, NULL, 0, eArgTypeNone, "Delete from every category."},
+ { LLDB_OPT_SET_2, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Delete from given category."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#endif // #ifndef LLDB_DISABLE_PYTHON
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeFilterClear
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeFilterClear : public CommandObjectParsed
+{
+private:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_delete_all = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_delete_all = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_delete_all;
+ bool m_delete_named;
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ static bool
+ PerCategoryCallback(void* param,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+ cate->Clear(eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter);
+ return true;
+
+ }
+
+public:
+ CommandObjectTypeFilterClear (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type filter clear",
+ "Delete all existing filters.",
+ NULL),
+ m_options(interpreter)
+ {
+ }
+
+ ~CommandObjectTypeFilterClear ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ if (m_options.m_delete_all)
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback, NULL);
+
+ else
+ {
+ lldb::TypeCategoryImplSP category;
+ if (command.GetArgumentCount() > 0)
+ {
+ const char* cat_name = command.GetArgumentAtIndex(0);
+ ConstString cat_nameCS(cat_name);
+ DataVisualization::Categories::GetCategory(cat_nameCS, category);
+ }
+ else
+ DataVisualization::Categories::GetCategory(ConstString(NULL), category);
+ category->GetFilterNavigator()->Clear();
+ category->GetRegexFilterNavigator()->Clear();
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+OptionDefinition
+CommandObjectTypeFilterClear::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "all", 'a', no_argument, NULL, 0, eArgTypeNone, "Clear every category."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#ifndef LLDB_DISABLE_PYTHON
+//-------------------------------------------------------------------------
+// CommandObjectTypeSynthClear
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeSynthClear : public CommandObjectParsed
+{
+private:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_delete_all = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_delete_all = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_delete_all;
+ bool m_delete_named;
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ static bool
+ PerCategoryCallback(void* param,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+ cate->Clear(eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth);
+ return true;
+
+ }
+
+public:
+ CommandObjectTypeSynthClear (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type synthetic clear",
+ "Delete all existing synthetic providers.",
+ NULL),
+ m_options(interpreter)
+ {
+ }
+
+ ~CommandObjectTypeSynthClear ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ if (m_options.m_delete_all)
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback, NULL);
+
+ else
+ {
+ lldb::TypeCategoryImplSP category;
+ if (command.GetArgumentCount() > 0)
+ {
+ const char* cat_name = command.GetArgumentAtIndex(0);
+ ConstString cat_nameCS(cat_name);
+ DataVisualization::Categories::GetCategory(cat_nameCS, category);
+ }
+ else
+ DataVisualization::Categories::GetCategory(ConstString(NULL), category);
+ category->GetSyntheticNavigator()->Clear();
+ category->GetRegexSyntheticNavigator()->Clear();
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+OptionDefinition
+CommandObjectTypeSynthClear::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "all", 'a', no_argument, NULL, 0, eArgTypeNone, "Clear every category."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// TypeSynthAddInputReader
+//-------------------------------------------------------------------------
+
+static const char *g_synth_addreader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n"
+ "You must define a Python class with these methods:\n"
+ " def __init__(self, valobj, dict):\n"
+ " def num_children(self):\n"
+ " def get_child_at_index(self, index):\n"
+ " def get_child_index(self, name):\n"
+ "Optionally, you can also define a method:\n"
+ " def update(self):\n"
+ "if your synthetic provider is holding on to any per-object state variables (currently, this is not implemented because of the way LLDB handles instances of SBValue and you should not rely on object persistence and per-object state)\n"
+ "class synthProvider:";
+
+class TypeSynthAddInputReader : public InputReaderEZ
+{
+public:
+ TypeSynthAddInputReader(Debugger& debugger) :
+ InputReaderEZ(debugger)
+ {}
+
+ virtual
+ ~TypeSynthAddInputReader()
+ {
+ }
+
+ virtual void ActivateHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ if (!batch_mode)
+ {
+ out_stream->Printf ("%s\n", g_synth_addreader_instructions);
+ if (data.reader.GetPrompt())
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+
+ virtual void ReactivateHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ if (data.reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+ virtual void GotTokenHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ if (data.bytes && data.bytes_len && data.baton)
+ {
+ ((SynthAddOptions*)data.baton)->m_user_source.AppendString(data.bytes, data.bytes_len);
+ }
+ if (!data.reader.IsDone() && data.reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+ virtual void InterruptHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ data.reader.SetIsDone (true);
+ if (!batch_mode)
+ {
+ out_stream->Printf ("Warning: No command attached to breakpoint.\n");
+ out_stream->Flush();
+ }
+ }
+ virtual void EOFHandler(HandlerData& data)
+ {
+ data.reader.SetIsDone (true);
+ }
+ virtual void DoneHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ SynthAddOptions *options_ptr = ((SynthAddOptions*)data.baton);
+ if (!options_ptr)
+ {
+ out_stream->Printf ("internal synchronization data missing.\n");
+ out_stream->Flush();
+ return;
+ }
+
+ SynthAddOptions::SharedPointer options(options_ptr); // this will ensure that we get rid of the pointer when going out of scope
+
+ ScriptInterpreter *interpreter = data.reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (!interpreter)
+ {
+ out_stream->Printf ("no script interpreter.\n");
+ out_stream->Flush();
+ return;
+ }
+ std::string class_name_str;
+ if (!interpreter->GenerateTypeSynthClass (options->m_user_source,
+ class_name_str))
+ {
+ out_stream->Printf ("unable to generate a class.\n");
+ out_stream->Flush();
+ return;
+ }
+ if (class_name_str.empty())
+ {
+ out_stream->Printf ("unable to obtain a proper name for the class.\n");
+ out_stream->Flush();
+ return;
+ }
+
+ // everything should be fine now, let's add the synth provider class
+
+ SyntheticChildrenSP synth_provider;
+ synth_provider.reset(new ScriptedSyntheticChildren(SyntheticChildren::Flags().SetCascades(options->m_cascade).
+ SetSkipPointers(options->m_skip_pointers).
+ SetSkipReferences(options->m_skip_references),
+ class_name_str.c_str()));
+
+
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(options->m_category.c_str()), category);
+
+ Error error;
+
+ for (size_t i = 0; i < options->m_target_types.GetSize(); i++)
+ {
+ const char *type_name = options->m_target_types.GetStringAtIndex(i);
+ ConstString typeCS(type_name);
+ if (typeCS)
+ {
+ if (!CommandObjectTypeSynthAdd::AddSynth(typeCS,
+ synth_provider,
+ options->m_regex ? CommandObjectTypeSynthAdd::eRegexSynth : CommandObjectTypeSynthAdd::eRegularSynth,
+ options->m_category,
+ &error))
+ {
+ out_stream->Printf("%s\n", error.AsCString());
+ out_stream->Flush();
+ return;
+ }
+ }
+ else
+ {
+ out_stream->Printf ("invalid type name.\n");
+ out_stream->Flush();
+ return;
+ }
+ }
+ }
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (TypeSynthAddInputReader);
+};
+
+void
+CommandObjectTypeSynthAdd::CollectPythonScript (SynthAddOptions *options,
+ CommandReturnObject &result)
+{
+ InputReaderSP reader_sp (new TypeSynthAddInputReader(m_interpreter.GetDebugger()));
+ if (reader_sp && options)
+ {
+
+ InputReaderEZ::InitializationParameters ipr;
+
+ Error err (reader_sp->Initialize (ipr.SetBaton(options).SetPrompt(" ")));
+ if (err.Success())
+ {
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+}
+
+bool
+CommandObjectTypeSynthAdd::Execute_HandwritePython (Args& command, CommandReturnObject &result)
+{
+ SynthAddOptions *options = new SynthAddOptions ( m_options.m_skip_pointers,
+ m_options.m_skip_references,
+ m_options.m_cascade,
+ m_options.m_regex,
+ m_options.m_category);
+
+ const size_t argc = command.GetArgumentCount();
+
+ for (size_t i = 0; i < argc; i++)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ if (typeA && *typeA)
+ options->m_target_types << typeA;
+ else
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ CollectPythonScript(options,result);
+ return result.Succeeded();
+}
+
+bool
+CommandObjectTypeSynthAdd::Execute_PythonClass (Args& command, CommandReturnObject &result)
+{
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1)
+ {
+ result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_class_name.empty() && !m_options.m_input_python)
+ {
+ result.AppendErrorWithFormat ("%s needs either a Python class name or -P to directly input Python code.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ SyntheticChildrenSP entry;
+
+ ScriptedSyntheticChildren* impl = new ScriptedSyntheticChildren(SyntheticChildren::Flags().
+ SetCascades(m_options.m_cascade).
+ SetSkipPointers(m_options.m_skip_pointers).
+ SetSkipReferences(m_options.m_skip_references),
+ m_options.m_class_name.c_str());
+
+ entry.reset(impl);
+
+ ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
+
+ if (interpreter && interpreter->CheckObjectExists(impl->GetPythonClassName()) == false)
+ result.AppendWarning("The provided class does not exist - please define it before attempting to use this synthetic provider");
+
+ // now I have a valid provider, let's add it to every type
+
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category);
+
+ Error error;
+
+ for (size_t i = 0; i < argc; i++)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ ConstString typeCS(typeA);
+ if (typeCS)
+ {
+ if (!AddSynth(typeCS,
+ entry,
+ m_options.m_regex ? eRegexSynth : eRegularSynth,
+ m_options.m_category,
+ &error))
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+}
+
+CommandObjectTypeSynthAdd::CommandObjectTypeSynthAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type synthetic add",
+ "Add a new synthetic provider for a type.",
+ NULL),
+ m_options (interpreter)
+{
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlus;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+}
+
+bool
+CommandObjectTypeSynthAdd::AddSynth(ConstString type_name,
+ SyntheticChildrenSP entry,
+ SynthFormatType type,
+ std::string category_name,
+ Error* error)
+{
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()), category);
+
+ if (type == eRegularSynth)
+ {
+ std::string type_name_str(type_name.GetCString());
+ if (type_name_str.compare(type_name_str.length() - 2, 2, "[]") == 0)
+ {
+ type_name_str.resize(type_name_str.length()-2);
+ if (type_name_str.back() != ' ')
+ type_name_str.append(" \\[[0-9]+\\]");
+ else
+ type_name_str.append("\\[[0-9]+\\]");
+ type_name.SetCString(type_name_str.c_str());
+ type = eRegularSynth;
+ }
+ }
+
+ if (category->AnyMatches(type_name,
+ eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter,
+ false))
+ {
+ if (error)
+ error->SetErrorStringWithFormat("cannot add synthetic for type %s when filter is defined in same category!", type_name.AsCString());
+ return false;
+ }
+
+ if (type == eRegexSynth)
+ {
+ RegularExpressionSP typeRX(new RegularExpression());
+ if (!typeRX->Compile(type_name.GetCString()))
+ {
+ if (error)
+ error->SetErrorString("regex format error (maybe this is not really a regex?)");
+ return false;
+ }
+
+ category->GetRegexSyntheticNavigator()->Delete(type_name);
+ category->GetRegexSyntheticNavigator()->Add(typeRX, entry);
+
+ return true;
+ }
+ else
+ {
+ category->GetSyntheticNavigator()->Add(type_name, entry);
+ return true;
+ }
+}
+
+bool
+CommandObjectTypeSynthAdd::DoExecute (Args& command, CommandReturnObject &result)
+{
+ if (m_options.handwrite_python)
+ return Execute_HandwritePython(command, result);
+ else if (m_options.is_class_based)
+ return Execute_PythonClass(command, result);
+ else
+ {
+ result.AppendError("must either provide a children list, a Python class name, or use -P and type a Python class line-by-line");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+}
+
+OptionDefinition
+CommandObjectTypeSynthAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
+ { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "skip-references", 'r', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
+ { LLDB_OPT_SET_2, false, "python-class", 'l', required_argument, NULL, 0, eArgTypePythonClass, "Use this Python class to produce synthetic children."},
+ { LLDB_OPT_SET_3, false, "input-python", 'P', no_argument, NULL, 0, eArgTypeNone, "Type Python code to generate a class that provides synthetic children."},
+ { LLDB_OPT_SET_ALL, false, "regex", 'x', no_argument, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#endif // #ifndef LLDB_DISABLE_PYTHON
+
+class CommandObjectTypeFilterAdd : public CommandObjectParsed
+{
+
+private:
+
+ class CommandOptions : public Options
+ {
+ typedef std::vector<std::string> option_vector;
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+ bool success;
+
+ switch (short_option)
+ {
+ case 'C':
+ m_cascade = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for cascade: %s", option_arg);
+ break;
+ case 'c':
+ m_expr_paths.push_back(option_arg);
+ has_child_list = true;
+ break;
+ case 'p':
+ m_skip_pointers = true;
+ break;
+ case 'r':
+ m_skip_references = true;
+ break;
+ case 'w':
+ m_category = std::string(option_arg);
+ break;
+ case 'x':
+ m_regex = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_cascade = true;
+ m_skip_pointers = false;
+ m_skip_references = false;
+ m_category = "default";
+ m_expr_paths.clear();
+ has_child_list = false;
+ m_regex = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_cascade;
+ bool m_skip_references;
+ bool m_skip_pointers;
+ bool m_input_python;
+ option_vector m_expr_paths;
+ std::string m_category;
+
+ bool has_child_list;
+
+ bool m_regex;
+
+ typedef option_vector::iterator ExpressionPathsIterator;
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ enum FilterFormatType
+ {
+ eRegularFilter,
+ eRegexFilter
+ };
+
+ bool
+ AddFilter(ConstString type_name,
+ SyntheticChildrenSP entry,
+ FilterFormatType type,
+ std::string category_name,
+ Error* error)
+ {
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()), category);
+
+ if (type == eRegularFilter)
+ {
+ std::string type_name_str(type_name.GetCString());
+ if (type_name_str.compare(type_name_str.length() - 2, 2, "[]") == 0)
+ {
+ type_name_str.resize(type_name_str.length()-2);
+ if (type_name_str.back() != ' ')
+ type_name_str.append(" \\[[0-9]+\\]");
+ else
+ type_name_str.append("\\[[0-9]+\\]");
+ type_name.SetCString(type_name_str.c_str());
+ type = eRegexFilter;
+ }
+ }
+
+ if (category->AnyMatches(type_name,
+ eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth,
+ false))
+ {
+ if (error)
+ error->SetErrorStringWithFormat("cannot add filter for type %s when synthetic is defined in same category!", type_name.AsCString());
+ return false;
+ }
+
+ if (type == eRegexFilter)
+ {
+ RegularExpressionSP typeRX(new RegularExpression());
+ if (!typeRX->Compile(type_name.GetCString()))
+ {
+ if (error)
+ error->SetErrorString("regex format error (maybe this is not really a regex?)");
+ return false;
+ }
+
+ category->GetRegexFilterNavigator()->Delete(type_name);
+ category->GetRegexFilterNavigator()->Add(typeRX, entry);
+
+ return true;
+ }
+ else
+ {
+ category->GetFilterNavigator()->Add(type_name, entry);
+ return true;
+ }
+ }
+
+
+public:
+
+ CommandObjectTypeFilterAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type filter add",
+ "Add a new filter for a type.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlus;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ SetHelpLong(
+ "Some examples of using this command.\n"
+ "We use as reference the following snippet of code:\n"
+ "\n"
+ "class Foo {;\n"
+ " int a;\n"
+ " int b;\n"
+ " int c;\n"
+ " int d;\n"
+ " int e;\n"
+ " int f;\n"
+ " int g;\n"
+ " int h;\n"
+ " int i;\n"
+ "} \n"
+ "Typing:\n"
+ "type filter add --child a --child g Foo\n"
+ "frame variable a_foo\n"
+ "will produce an output where only a and g are displayed\n"
+ "Other children of a_foo (b,c,d,e,f,h and i) are available by asking for them, as in:\n"
+ "frame variable a_foo.b a_foo.c ... a_foo.i\n"
+ "\n"
+ "Use option --raw to frame variable prevails on the filter\n"
+ "frame variable a_foo --raw\n"
+ "shows all the children of a_foo (a thru i) as if no filter was defined\n"
+ );
+ }
+
+ ~CommandObjectTypeFilterAdd ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1)
+ {
+ result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_expr_paths.size() == 0)
+ {
+ result.AppendErrorWithFormat ("%s needs one or more children.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ SyntheticChildrenSP entry;
+
+ TypeFilterImpl* impl = new TypeFilterImpl(SyntheticChildren::Flags().SetCascades(m_options.m_cascade).
+ SetSkipPointers(m_options.m_skip_pointers).
+ SetSkipReferences(m_options.m_skip_references));
+
+ entry.reset(impl);
+
+ // go through the expression paths
+ CommandOptions::ExpressionPathsIterator begin, end = m_options.m_expr_paths.end();
+
+ for (begin = m_options.m_expr_paths.begin(); begin != end; begin++)
+ impl->AddExpressionPath(*begin);
+
+
+ // now I have a valid provider, let's add it to every type
+
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category);
+
+ Error error;
+
+ for (size_t i = 0; i < argc; i++)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ ConstString typeCS(typeA);
+ if (typeCS)
+ {
+ if (!AddFilter(typeCS,
+ entry,
+ m_options.m_regex ? eRegexFilter : eRegularFilter,
+ m_options.m_category,
+ &error))
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+
+};
+
+OptionDefinition
+CommandObjectTypeFilterAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
+ { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "skip-references", 'r', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
+ { LLDB_OPT_SET_ALL, false, "child", 'c', required_argument, NULL, 0, eArgTypeExpressionPath, "Include this expression path in the synthetic view."},
+ { LLDB_OPT_SET_ALL, false, "regex", 'x', no_argument, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+class CommandObjectTypeFormat : public CommandObjectMultiword
+{
+public:
+ CommandObjectTypeFormat (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "type format",
+ "A set of commands for editing variable value display options",
+ "type format [<sub-command-options>] ")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeFormatAdd (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeFormatClear (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeFormatDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeFormatList (interpreter)));
+ }
+
+
+ ~CommandObjectTypeFormat ()
+ {
+ }
+};
+
+#ifndef LLDB_DISABLE_PYTHON
+
+class CommandObjectTypeSynth : public CommandObjectMultiword
+{
+public:
+ CommandObjectTypeSynth (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "type synthetic",
+ "A set of commands for operating on synthetic type representations",
+ "type synthetic [<sub-command-options>] ")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeSynthAdd (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeSynthClear (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeSynthDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeSynthList (interpreter)));
+ }
+
+
+ ~CommandObjectTypeSynth ()
+ {
+ }
+};
+
+#endif // #ifndef LLDB_DISABLE_PYTHON
+
+class CommandObjectTypeFilter : public CommandObjectMultiword
+{
+public:
+ CommandObjectTypeFilter (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "type filter",
+ "A set of commands for operating on type filters",
+ "type synthetic [<sub-command-options>] ")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeFilterAdd (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeFilterClear (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeFilterDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeFilterList (interpreter)));
+ }
+
+
+ ~CommandObjectTypeFilter ()
+ {
+ }
+};
+
+class CommandObjectTypeCategory : public CommandObjectMultiword
+{
+public:
+ CommandObjectTypeCategory (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "type category",
+ "A set of commands for operating on categories",
+ "type category [<sub-command-options>] ")
+ {
+ LoadSubCommand ("enable", CommandObjectSP (new CommandObjectTypeCategoryEnable (interpreter)));
+ LoadSubCommand ("disable", CommandObjectSP (new CommandObjectTypeCategoryDisable (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeCategoryDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeCategoryList (interpreter)));
+ }
+
+
+ ~CommandObjectTypeCategory ()
+ {
+ }
+};
+
+class CommandObjectTypeSummary : public CommandObjectMultiword
+{
+public:
+ CommandObjectTypeSummary (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "type summary",
+ "A set of commands for editing variable summary display options",
+ "type summary [<sub-command-options>] ")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeSummaryAdd (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeSummaryClear (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeSummaryDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeSummaryList (interpreter)));
+ }
+
+
+ ~CommandObjectTypeSummary ()
+ {
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectType
+//-------------------------------------------------------------------------
+
+CommandObjectType::CommandObjectType (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "type",
+ "A set of commands for operating on the type system",
+ "type [<sub-command-options>]")
+{
+ LoadSubCommand ("category", CommandObjectSP (new CommandObjectTypeCategory (interpreter)));
+ LoadSubCommand ("filter", CommandObjectSP (new CommandObjectTypeFilter (interpreter)));
+ LoadSubCommand ("format", CommandObjectSP (new CommandObjectTypeFormat (interpreter)));
+ LoadSubCommand ("summary", CommandObjectSP (new CommandObjectTypeSummary (interpreter)));
+#ifndef LLDB_DISABLE_PYTHON
+ LoadSubCommand ("synthetic", CommandObjectSP (new CommandObjectTypeSynth (interpreter)));
+#endif
+}
+
+
+CommandObjectType::~CommandObjectType ()
+{
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectType.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectType.h
new file mode 100644
index 0000000..c796902
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectType.h
@@ -0,0 +1,37 @@
+//===-- CommandObjectType.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_CommandObjectType_h_
+#define liblldb_CommandObjectType_h_
+
+// C Includes
+// C++ Includes
+
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-types.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/Options.h"
+
+namespace lldb_private {
+
+class CommandObjectType : public CommandObjectMultiword
+{
+public:
+ CommandObjectType (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectType ();
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectType_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectVersion.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectVersion.cpp
new file mode 100644
index 0000000..2d950a8
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectVersion.cpp
@@ -0,0 +1,53 @@
+//===-- CommandObjectVersion.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 "CommandObjectVersion.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectVersion
+//-------------------------------------------------------------------------
+
+CommandObjectVersion::CommandObjectVersion (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter, "version", "Show version of LLDB debugger.", "version")
+{
+}
+
+CommandObjectVersion::~CommandObjectVersion ()
+{
+}
+
+bool
+CommandObjectVersion::DoExecute (Args& args, CommandReturnObject &result)
+{
+ if (args.GetArgumentCount() == 0)
+ {
+ result.AppendMessageWithFormat ("%s\n", lldb_private::GetVersion());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError("the version command takes no arguments.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return true;
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectVersion.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectVersion.h
new file mode 100644
index 0000000..1fdbed6
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectVersion.h
@@ -0,0 +1,43 @@
+//===-- CommandObjectVersion.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_CommandObjectVersion_h_
+#define liblldb_CommandObjectVersion_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectVersion
+//-------------------------------------------------------------------------
+
+class CommandObjectVersion : public CommandObjectParsed
+{
+public:
+
+ CommandObjectVersion (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectVersion ();
+
+protected:
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectVersion_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpoint.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpoint.cpp
new file mode 100644
index 0000000..6f70f39
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpoint.cpp
@@ -0,0 +1,1394 @@
+//===-- CommandObjectWatchpoint.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 "CommandObjectWatchpoint.h"
+#include "CommandObjectWatchpointCommand.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Breakpoint/WatchpointList.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Target.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static void
+AddWatchpointDescription(Stream *s, Watchpoint *wp, lldb::DescriptionLevel level)
+{
+ s->IndentMore();
+ wp->GetDescription(s, level);
+ s->IndentLess();
+ s->EOL();
+}
+
+static bool
+CheckTargetForWatchpointOperations(Target *target, CommandReturnObject &result)
+{
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No existing target or watchpoints.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ bool process_is_valid = target->GetProcessSP() && target->GetProcessSP()->IsAlive();
+ if (!process_is_valid)
+ {
+ result.AppendError ("Thre's no process or it is not alive.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ // Target passes our checks, return true.
+ return true;
+}
+
+// FIXME: This doesn't seem to be the right place for this functionality.
+#include "llvm/ADT/StringRef.h"
+static inline void StripLeadingSpaces(llvm::StringRef &Str)
+{
+ while (!Str.empty() && isspace(Str[0]))
+ Str = Str.substr(1);
+}
+
+// Equivalent class: {"-", "to", "To", "TO"} of range specifier array.
+static const char* RSA[4] = { "-", "to", "To", "TO" };
+
+// Return the index to RSA if found; otherwise -1 is returned.
+static int32_t
+WithRSAIndex(llvm::StringRef &Arg)
+{
+
+ uint32_t i;
+ for (i = 0; i < 4; ++i)
+ if (Arg.find(RSA[i]) != llvm::StringRef::npos)
+ return i;
+ return -1;
+}
+
+// Return true if wp_ids is successfully populated with the watch ids.
+// False otherwise.
+bool
+CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(Target *target, Args &args, std::vector<uint32_t> &wp_ids)
+{
+ // Pre-condition: args.GetArgumentCount() > 0.
+ if (args.GetArgumentCount() == 0)
+ {
+ if (target == NULL)
+ return false;
+ WatchpointSP watch_sp = target->GetLastCreatedWatchpoint();
+ if (watch_sp)
+ {
+ wp_ids.push_back(watch_sp->GetID());
+ return true;
+ }
+ else
+ return false;
+ }
+
+ llvm::StringRef Minus("-");
+ std::vector<llvm::StringRef> StrRefArgs;
+ std::pair<llvm::StringRef, llvm::StringRef> Pair;
+ size_t i;
+ int32_t idx;
+ // Go through the argments and make a canonical form of arg list containing
+ // only numbers with possible "-" in between.
+ for (i = 0; i < args.GetArgumentCount(); ++i) {
+ llvm::StringRef Arg(args.GetArgumentAtIndex(i));
+ if ((idx = WithRSAIndex(Arg)) == -1) {
+ StrRefArgs.push_back(Arg);
+ continue;
+ }
+ // The Arg contains the range specifier, split it, then.
+ Pair = Arg.split(RSA[idx]);
+ if (!Pair.first.empty())
+ StrRefArgs.push_back(Pair.first);
+ StrRefArgs.push_back(Minus);
+ if (!Pair.second.empty())
+ StrRefArgs.push_back(Pair.second);
+ }
+ // Now process the canonical list and fill in the vector of uint32_t's.
+ // If there is any error, return false and the client should ignore wp_ids.
+ uint32_t beg, end, id;
+ size_t size = StrRefArgs.size();
+ bool in_range = false;
+ for (i = 0; i < size; ++i) {
+ llvm::StringRef Arg = StrRefArgs[i];
+ if (in_range) {
+ // Look for the 'end' of the range. Note StringRef::getAsInteger()
+ // returns true to signify error while parsing.
+ if (Arg.getAsInteger(0, end))
+ return false;
+ // Found a range! Now append the elements.
+ for (id = beg; id <= end; ++id)
+ wp_ids.push_back(id);
+ in_range = false;
+ continue;
+ }
+ if (i < (size - 1) && StrRefArgs[i+1] == Minus) {
+ if (Arg.getAsInteger(0, beg))
+ return false;
+ // Turn on the in_range flag, we are looking for end of range next.
+ ++i; in_range = true;
+ continue;
+ }
+ // Otherwise, we have a simple ID. Just append it.
+ if (Arg.getAsInteger(0, beg))
+ return false;
+ wp_ids.push_back(beg);
+ }
+ // It is an error if after the loop, we're still in_range.
+ if (in_range)
+ return false;
+
+ return true; // Success!
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointList
+//-------------------------------------------------------------------------
+#pragma mark List
+
+class CommandObjectWatchpointList : public CommandObjectParsed
+{
+public:
+ CommandObjectWatchpointList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "watchpoint list",
+ "List all watchpoints at configurable levels of detail.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back(arg);
+ }
+
+ virtual
+ ~CommandObjectWatchpointList () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter),
+ m_level(lldb::eDescriptionLevelBrief) // Watchpoint List defaults to brief descriptions
+ {
+ }
+
+ virtual
+ ~CommandOptions () {}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'b':
+ m_level = lldb::eDescriptionLevelBrief;
+ break;
+ case 'f':
+ m_level = lldb::eDescriptionLevelFull;
+ break;
+ case 'v':
+ m_level = lldb::eDescriptionLevelVerbose;
+ break;
+ default:
+ error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_level = lldb::eDescriptionLevelFull;
+ }
+
+ const OptionDefinition *
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ lldb::DescriptionLevel m_level;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No current target or watchpoints.");
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+ if (target->GetProcessSP() && target->GetProcessSP()->IsAlive())
+ {
+ uint32_t num_supported_hardware_watchpoints;
+ Error error = target->GetProcessSP()->GetWatchpointSupportInfo(num_supported_hardware_watchpoints);
+ if (error.Success())
+ result.AppendMessageWithFormat("Number of supported hardware watchpoints: %u\n",
+ num_supported_hardware_watchpoints);
+ }
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+ Mutex::Locker locker;
+ target->GetWatchpointList().GetListMutex(locker);
+
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendMessage("No watchpoints currently set.");
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+ Stream &output_stream = result.GetOutputStream();
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // No watchpoint selected; show info about all currently set watchpoints.
+ result.AppendMessage ("Current watchpoints:");
+ for (size_t i = 0; i < num_watchpoints; ++i)
+ {
+ Watchpoint *wp = watchpoints.GetByIndex(i).get();
+ AddWatchpointDescription(&output_stream, wp, m_options.m_level);
+ }
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular watchpoints selected; enable them.
+ std::vector<uint32_t> wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const size_t size = wp_ids.size();
+ for (size_t i = 0; i < size; ++i)
+ {
+ Watchpoint *wp = watchpoints.FindByID(wp_ids[i]).get();
+ if (wp)
+ AddWatchpointDescription(&output_stream, wp, m_options.m_level);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointList::Options
+//-------------------------------------------------------------------------
+#pragma mark List::CommandOptions
+OptionDefinition
+CommandObjectWatchpointList::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "brief", 'b', no_argument, NULL, 0, eArgTypeNone,
+ "Give a brief description of the watchpoint (no location info)."},
+
+ { LLDB_OPT_SET_2, false, "full", 'f', no_argument, NULL, 0, eArgTypeNone,
+ "Give a full description of the watchpoint and its locations."},
+
+ { LLDB_OPT_SET_3, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone,
+ "Explain everything we know about the watchpoint (for debugging debugger bugs)." },
+
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointEnable
+//-------------------------------------------------------------------------
+#pragma mark Enable
+
+class CommandObjectWatchpointEnable : public CommandObjectParsed
+{
+public:
+ CommandObjectWatchpointEnable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "enable",
+ "Enable the specified disabled watchpoint(s). If no watchpoints are specified, enable all of them.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back(arg);
+ }
+
+ virtual
+ ~CommandObjectWatchpointEnable () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (!CheckTargetForWatchpointOperations(target, result))
+ return false;
+
+ Mutex::Locker locker;
+ target->GetWatchpointList().GetListMutex(locker);
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError("No watchpoints exist to be enabled.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // No watchpoint selected; enable all currently set watchpoints.
+ target->EnableAllWatchpoints();
+ result.AppendMessageWithFormat("All watchpoints enabled. (%lu watchpoints)\n", num_watchpoints);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular watchpoints selected; enable them.
+ std::vector<uint32_t> wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ int count = 0;
+ const size_t size = wp_ids.size();
+ for (size_t i = 0; i < size; ++i)
+ if (target->EnableWatchpointByID(wp_ids[i]))
+ ++count;
+ result.AppendMessageWithFormat("%d watchpoints enabled.\n", count);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointDisable
+//-------------------------------------------------------------------------
+#pragma mark Disable
+
+class CommandObjectWatchpointDisable : public CommandObjectParsed
+{
+public:
+ CommandObjectWatchpointDisable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "watchpoint disable",
+ "Disable the specified watchpoint(s) without removing it/them. If no watchpoints are specified, disable them all.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back(arg);
+ }
+
+
+ virtual
+ ~CommandObjectWatchpointDisable () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (!CheckTargetForWatchpointOperations(target, result))
+ return false;
+
+ Mutex::Locker locker;
+ target->GetWatchpointList().GetListMutex(locker);
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError("No watchpoints exist to be disabled.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // No watchpoint selected; disable all currently set watchpoints.
+ if (target->DisableAllWatchpoints())
+ {
+ result.AppendMessageWithFormat("All watchpoints disabled. (%lu watchpoints)\n", num_watchpoints);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError("Disable all watchpoints failed\n");
+ result.SetStatus(eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ // Particular watchpoints selected; disable them.
+ std::vector<uint32_t> wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ int count = 0;
+ const size_t size = wp_ids.size();
+ for (size_t i = 0; i < size; ++i)
+ if (target->DisableWatchpointByID(wp_ids[i]))
+ ++count;
+ result.AppendMessageWithFormat("%d watchpoints disabled.\n", count);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointDelete
+//-------------------------------------------------------------------------
+#pragma mark Delete
+
+class CommandObjectWatchpointDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectWatchpointDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed(interpreter,
+ "watchpoint delete",
+ "Delete the specified watchpoint(s). If no watchpoints are specified, delete them all.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back(arg);
+ }
+
+ virtual
+ ~CommandObjectWatchpointDelete () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (!CheckTargetForWatchpointOperations(target, result))
+ return false;
+
+ Mutex::Locker locker;
+ target->GetWatchpointList().GetListMutex(locker);
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError("No watchpoints exist to be deleted.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ if (!m_interpreter.Confirm("About to delete all watchpoints, do you want to do that?", true))
+ {
+ result.AppendMessage("Operation cancelled...");
+ }
+ else
+ {
+ target->RemoveAllWatchpoints();
+ result.AppendMessageWithFormat("All watchpoints removed. (%lu watchpoints)\n", num_watchpoints);
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular watchpoints selected; delete them.
+ std::vector<uint32_t> wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ int count = 0;
+ const size_t size = wp_ids.size();
+ for (size_t i = 0; i < size; ++i)
+ if (target->RemoveWatchpointByID(wp_ids[i]))
+ ++count;
+ result.AppendMessageWithFormat("%d watchpoints deleted.\n",count);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointIgnore
+//-------------------------------------------------------------------------
+
+class CommandObjectWatchpointIgnore : public CommandObjectParsed
+{
+public:
+ CommandObjectWatchpointIgnore (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "watchpoint ignore",
+ "Set ignore count on the specified watchpoint(s). If no watchpoints are specified, set them all.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back(arg);
+ }
+
+ virtual
+ ~CommandObjectWatchpointIgnore () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_ignore_count (0)
+ {
+ }
+
+ virtual
+ ~CommandOptions () {}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'i':
+ {
+ m_ignore_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0);
+ if (m_ignore_count == UINT32_MAX)
+ error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg);
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_ignore_count = 0;
+ }
+
+ const OptionDefinition *
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ uint32_t m_ignore_count;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (!CheckTargetForWatchpointOperations(target, result))
+ return false;
+
+ Mutex::Locker locker;
+ target->GetWatchpointList().GetListMutex(locker);
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError("No watchpoints exist to be ignored.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ target->IgnoreAllWatchpoints(m_options.m_ignore_count);
+ result.AppendMessageWithFormat("All watchpoints ignored. (%lu watchpoints)\n", num_watchpoints);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular watchpoints selected; ignore them.
+ std::vector<uint32_t> wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ int count = 0;
+ const size_t size = wp_ids.size();
+ for (size_t i = 0; i < size; ++i)
+ if (target->IgnoreWatchpointByID(wp_ids[i], m_options.m_ignore_count))
+ ++count;
+ result.AppendMessageWithFormat("%d watchpoints ignored.\n",count);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+};
+
+#pragma mark Ignore::CommandOptions
+OptionDefinition
+CommandObjectWatchpointIgnore::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, true, "ignore-count", 'i', required_argument, NULL, 0, eArgTypeCount, "Set the number of times this watchpoint is skipped before stopping." },
+ { 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointModify
+//-------------------------------------------------------------------------
+#pragma mark Modify
+
+class CommandObjectWatchpointModify : public CommandObjectParsed
+{
+public:
+
+ CommandObjectWatchpointModify (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "watchpoint modify",
+ "Modify the options on a watchpoint or set of watchpoints in the executable. "
+ "If no watchpoint is specified, act on the last created watchpoint. "
+ "Passing an empty argument clears the modification.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectWatchpointModify () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_condition (),
+ m_condition_passed (false)
+ {
+ }
+
+ virtual
+ ~CommandOptions () {}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'c':
+ if (option_arg != NULL)
+ m_condition.assign (option_arg);
+ else
+ m_condition.clear();
+ m_condition_passed = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_condition.clear();
+ m_condition_passed = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ std::string m_condition;
+ bool m_condition_passed;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (!CheckTargetForWatchpointOperations(target, result))
+ return false;
+
+ Mutex::Locker locker;
+ target->GetWatchpointList().GetListMutex(locker);
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError("No watchpoints exist to be modified.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ WatchpointSP wp_sp = target->GetLastCreatedWatchpoint();
+ wp_sp->SetCondition(m_options.m_condition.c_str());
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular watchpoints selected; set condition on them.
+ std::vector<uint32_t> wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ int count = 0;
+ const size_t size = wp_ids.size();
+ for (size_t i = 0; i < size; ++i)
+ {
+ WatchpointSP wp_sp = watchpoints.FindByID(wp_ids[i]);
+ if (wp_sp)
+ {
+ wp_sp->SetCondition(m_options.m_condition.c_str());
+ ++count;
+ }
+ }
+ result.AppendMessageWithFormat("%d watchpoints modified.\n",count);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+};
+
+#pragma mark Modify::CommandOptions
+OptionDefinition
+CommandObjectWatchpointModify::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "condition", 'c', required_argument, NULL, 0, eArgTypeExpression, "The watchpoint stops only if this condition expression evaluates to true."},
+{ 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointSetVariable
+//-------------------------------------------------------------------------
+#pragma mark SetVariable
+
+class CommandObjectWatchpointSetVariable : public CommandObjectParsed
+{
+public:
+
+ CommandObjectWatchpointSetVariable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "watchpoint set variable",
+ "Set a watchpoint on a variable. "
+ "Use the '-w' option to specify the type of watchpoint and "
+ "the '-x' option to specify the byte size to watch for. "
+ "If no '-w' option is specified, it defaults to write. "
+ "If no '-x' option is specified, it defaults to the variable's "
+ "byte size. "
+ "Note that there are limited hardware resources for watchpoints. "
+ "If watchpoint setting fails, consider disable/delete existing ones "
+ "to free up resources.",
+ NULL,
+ eFlagRequiresFrame |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_option_group (interpreter),
+ m_option_watchpoint ()
+ {
+ SetHelpLong(
+ "Examples: \n\
+ \n\
+ watchpoint set variable -w read_wriate my_global_var \n\
+ # Watch my_global_var for read/write access, with the region to watch corresponding to the byte size of the data type.\n");
+
+ CommandArgumentEntry arg;
+ CommandArgumentData var_name_arg;
+
+ // Define the only variant of this arg.
+ var_name_arg.arg_type = eArgTypeVarName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // Push the variant into the argument entry.
+ arg.push_back (var_name_arg);
+
+ // Push the data for the only argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+ // Absorb the '-w' and '-x' options into our option group.
+ m_option_group.Append (&m_option_watchpoint, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectWatchpointSetVariable () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+ static size_t GetVariableCallback (void *baton,
+ const char *name,
+ VariableList &variable_list)
+ {
+ Target *target = static_cast<Target *>(baton);
+ if (target)
+ {
+ return target->GetImages().FindGlobalVariables (ConstString(name),
+ true,
+ UINT32_MAX,
+ variable_list);
+ }
+ return 0;
+ }
+
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+
+ // If no argument is present, issue an error message. There's no way to set a watchpoint.
+ if (command.GetArgumentCount() <= 0)
+ {
+ result.GetErrorStream().Printf("error: required argument missing; specify your program variable to watch for\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ // If no '-w' is specified, default to '-w write'.
+ if (!m_option_watchpoint.watch_type_specified)
+ {
+ m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite;
+ }
+
+ // We passed the sanity check for the command.
+ // Proceed to set the watchpoint now.
+ lldb::addr_t addr = 0;
+ size_t size = 0;
+
+ VariableSP var_sp;
+ ValueObjectSP valobj_sp;
+ Stream &output_stream = result.GetOutputStream();
+
+ // A simple watch variable gesture allows only one argument.
+ if (command.GetArgumentCount() != 1)
+ {
+ result.GetErrorStream().Printf("error: specify exactly one variable to watch for\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ // Things have checked out ok...
+ Error error;
+ uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember |
+ StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
+ valobj_sp = frame->GetValueForVariableExpressionPath (command.GetArgumentAtIndex(0),
+ eNoDynamicValues,
+ expr_path_options,
+ var_sp,
+ error);
+
+ if (!valobj_sp)
+ {
+ // Not in the frame; let's check the globals.
+
+ VariableList variable_list;
+ ValueObjectList valobj_list;
+
+ Error error (Variable::GetValuesForVariableExpressionPath (command.GetArgumentAtIndex(0),
+ m_exe_ctx.GetBestExecutionContextScope(),
+ GetVariableCallback,
+ target,
+ variable_list,
+ valobj_list));
+
+ if (valobj_list.GetSize())
+ valobj_sp = valobj_list.GetValueObjectAtIndex(0);
+ }
+
+ ClangASTType clang_type;
+
+ if (valobj_sp)
+ {
+ AddressType addr_type;
+ addr = valobj_sp->GetAddressOf(false, &addr_type);
+ if (addr_type == eAddressTypeLoad)
+ {
+ // We're in business.
+ // Find out the size of this variable.
+ size = m_option_watchpoint.watch_size == 0 ? valobj_sp->GetByteSize()
+ : m_option_watchpoint.watch_size;
+ }
+ clang_type = valobj_sp->GetClangType();
+ }
+ else
+ {
+ const char *error_cstr = error.AsCString(NULL);
+ if (error_cstr)
+ result.GetErrorStream().Printf("error: %s\n", error_cstr);
+ else
+ result.GetErrorStream().Printf ("error: unable to find any variable expression path that matches '%s'\n",
+ command.GetArgumentAtIndex(0));
+ return false;
+ }
+
+ // Now it's time to create the watchpoint.
+ uint32_t watch_type = m_option_watchpoint.watch_type;
+
+ error.Clear();
+ Watchpoint *wp = target->CreateWatchpoint(addr, size, &clang_type, watch_type, error).get();
+ if (wp)
+ {
+ wp->SetWatchSpec(command.GetArgumentAtIndex(0));
+ wp->SetWatchVariable(true);
+ if (var_sp && var_sp->GetDeclaration().GetFile())
+ {
+ StreamString ss;
+ // True to show fullpath for declaration file.
+ var_sp->GetDeclaration().DumpStopContext(&ss, true);
+ wp->SetDeclInfo(ss.GetString());
+ }
+ output_stream.Printf("Watchpoint created: ");
+ wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull);
+ output_stream.EOL();
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64 ", size=%lu, variable expression='%s').\n",
+ addr, size, command.GetArgumentAtIndex(0));
+ if (error.AsCString(NULL))
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ OptionGroupOptions m_option_group;
+ OptionGroupWatchpoint m_option_watchpoint;
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointSetExpression
+//-------------------------------------------------------------------------
+#pragma mark Set
+
+class CommandObjectWatchpointSetExpression : public CommandObjectRaw
+{
+public:
+
+ CommandObjectWatchpointSetExpression (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "watchpoint set expression",
+ "Set a watchpoint on an address by supplying an expression. "
+ "Use the '-w' option to specify the type of watchpoint and "
+ "the '-x' option to specify the byte size to watch for. "
+ "If no '-w' option is specified, it defaults to write. "
+ "If no '-x' option is specified, it defaults to the target's "
+ "pointer byte size. "
+ "Note that there are limited hardware resources for watchpoints. "
+ "If watchpoint setting fails, consider disable/delete existing ones "
+ "to free up resources.",
+ NULL,
+ eFlagRequiresFrame |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_option_group (interpreter),
+ m_option_watchpoint ()
+ {
+ SetHelpLong(
+ "Examples: \n\
+ \n\
+ watchpoint set expression -w write -x 1 -- foo + 32\n\
+ # Watch write access for the 1-byte region pointed to by the address 'foo + 32'.\n");
+
+ CommandArgumentEntry arg;
+ CommandArgumentData expression_arg;
+
+ // Define the only variant of this arg.
+ expression_arg.arg_type = eArgTypeExpression;
+ expression_arg.arg_repetition = eArgRepeatPlain;
+
+ // Push the only variant into the argument entry.
+ arg.push_back (expression_arg);
+
+ // Push the data for the only argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+ // Absorb the '-w' and '-x' options into our option group.
+ m_option_group.Append (&m_option_watchpoint, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+
+ virtual
+ ~CommandObjectWatchpointSetExpression () {}
+
+ // Overrides base class's behavior where WantsCompletion = !WantsRawCommandString.
+ virtual bool
+ WantsCompletion() { return true; }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *raw_command, CommandReturnObject &result)
+ {
+ m_option_group.NotifyOptionParsingStarting(); // This is a raw command, so notify the option group
+
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+
+ Args command(raw_command);
+ const char *expr = NULL;
+ if (raw_command[0] == '-')
+ {
+ // We have some options and these options MUST end with --.
+ const char *end_options = NULL;
+ const char *s = raw_command;
+ while (s && s[0])
+ {
+ end_options = ::strstr (s, "--");
+ if (end_options)
+ {
+ end_options += 2; // Get past the "--"
+ if (::isspace (end_options[0]))
+ {
+ expr = end_options;
+ while (::isspace (*expr))
+ ++expr;
+ break;
+ }
+ }
+ s = end_options;
+ }
+
+ if (end_options)
+ {
+ Args args (raw_command, end_options - raw_command);
+ if (!ParseOptions (args, result))
+ return false;
+
+ Error error (m_option_group.NotifyOptionParsingFinished());
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+
+ if (expr == NULL)
+ expr = raw_command;
+
+ // If no argument is present, issue an error message. There's no way to set a watchpoint.
+ if (command.GetArgumentCount() == 0)
+ {
+ result.GetErrorStream().Printf("error: required argument missing; specify an expression to evaulate into the address to watch for\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ // If no '-w' is specified, default to '-w write'.
+ if (!m_option_watchpoint.watch_type_specified)
+ {
+ m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite;
+ }
+
+ // We passed the sanity check for the command.
+ // Proceed to set the watchpoint now.
+ lldb::addr_t addr = 0;
+ size_t size = 0;
+
+ ValueObjectSP valobj_sp;
+
+ // Use expression evaluation to arrive at the address to watch.
+ EvaluateExpressionOptions options;
+ options.SetCoerceToId(false)
+ .SetUnwindOnError(true)
+ .SetKeepInMemory(false)
+ .SetRunOthers(true)
+ .SetTimeoutUsec(0);
+
+ ExecutionResults expr_result = target->EvaluateExpression (expr,
+ frame,
+ valobj_sp,
+ options);
+ if (expr_result != eExecutionCompleted)
+ {
+ result.GetErrorStream().Printf("error: expression evaluation of address to watch failed\n");
+ result.GetErrorStream().Printf("expression evaluated: %s\n", expr);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ // Get the address to watch.
+ bool success = false;
+ addr = valobj_sp->GetValueAsUnsigned(0, &success);
+ if (!success)
+ {
+ result.GetErrorStream().Printf("error: expression did not evaluate to an address\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_option_watchpoint.watch_size != 0)
+ size = m_option_watchpoint.watch_size;
+ else
+ size = target->GetArchitecture().GetAddressByteSize();
+
+ // Now it's time to create the watchpoint.
+ uint32_t watch_type = m_option_watchpoint.watch_type;
+
+ // Fetch the type from the value object, the type of the watched object is the pointee type
+ /// of the expression, so convert to that if we found a valid type.
+ ClangASTType clang_type(valobj_sp->GetClangType());
+
+ Error error;
+ Watchpoint *wp = target->CreateWatchpoint(addr, size, &clang_type, watch_type, error).get();
+ if (wp)
+ {
+ Stream &output_stream = result.GetOutputStream();
+ output_stream.Printf("Watchpoint created: ");
+ wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull);
+ output_stream.EOL();
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64 ", size=%lu).\n",
+ addr, size);
+ if (error.AsCString(NULL))
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ OptionGroupOptions m_option_group;
+ OptionGroupWatchpoint m_option_watchpoint;
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointSet
+//-------------------------------------------------------------------------
+#pragma mark Set
+
+class CommandObjectWatchpointSet : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectWatchpointSet (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "watchpoint set",
+ "A set of commands for setting a watchpoint.",
+ "watchpoint set <subcommand> [<subcommand-options>]")
+ {
+
+ LoadSubCommand ("variable", CommandObjectSP (new CommandObjectWatchpointSetVariable (interpreter)));
+ LoadSubCommand ("expression", CommandObjectSP (new CommandObjectWatchpointSetExpression (interpreter)));
+ }
+
+
+ virtual
+ ~CommandObjectWatchpointSet () {}
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordWatchpoint
+//-------------------------------------------------------------------------
+#pragma mark MultiwordWatchpoint
+
+CommandObjectMultiwordWatchpoint::CommandObjectMultiwordWatchpoint(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "watchpoint",
+ "A set of commands for operating on watchpoints.",
+ "watchpoint <command> [<command-options>]")
+{
+ CommandObjectSP list_command_object (new CommandObjectWatchpointList (interpreter));
+ CommandObjectSP enable_command_object (new CommandObjectWatchpointEnable (interpreter));
+ CommandObjectSP disable_command_object (new CommandObjectWatchpointDisable (interpreter));
+ CommandObjectSP delete_command_object (new CommandObjectWatchpointDelete (interpreter));
+ CommandObjectSP ignore_command_object (new CommandObjectWatchpointIgnore (interpreter));
+ CommandObjectSP command_command_object (new CommandObjectWatchpointCommand (interpreter));
+ CommandObjectSP modify_command_object (new CommandObjectWatchpointModify (interpreter));
+ CommandObjectSP set_command_object (new CommandObjectWatchpointSet (interpreter));
+
+ list_command_object->SetCommandName ("watchpoint list");
+ enable_command_object->SetCommandName("watchpoint enable");
+ disable_command_object->SetCommandName("watchpoint disable");
+ delete_command_object->SetCommandName("watchpoint delete");
+ ignore_command_object->SetCommandName("watchpoint ignore");
+ command_command_object->SetCommandName ("watchpoint command");
+ modify_command_object->SetCommandName("watchpoint modify");
+ set_command_object->SetCommandName("watchpoint set");
+
+ LoadSubCommand ("list", list_command_object);
+ LoadSubCommand ("enable", enable_command_object);
+ LoadSubCommand ("disable", disable_command_object);
+ LoadSubCommand ("delete", delete_command_object);
+ LoadSubCommand ("ignore", ignore_command_object);
+ LoadSubCommand ("command", command_command_object);
+ LoadSubCommand ("modify", modify_command_object);
+ LoadSubCommand ("set", set_command_object);
+}
+
+CommandObjectMultiwordWatchpoint::~CommandObjectMultiwordWatchpoint()
+{
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpoint.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpoint.h
new file mode 100644
index 0000000..1b1ebd7
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpoint.h
@@ -0,0 +1,43 @@
+//===-- CommandObjectWatchpoint.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_CommandObjectWatchpoint_h_
+#define liblldb_CommandObjectWatchpoint_h_
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionGroupWatchpoint.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordWatchpoint
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordWatchpoint : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordWatchpoint (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordWatchpoint ();
+
+ static bool
+ VerifyWatchpointIDs(Target *target, Args &args, std::vector<uint32_t> &wp_ids);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectWatchpoint_h_
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.cpp
new file mode 100644
index 0000000..4e20046
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.cpp
@@ -0,0 +1,850 @@
+//===-- CommandObjectWatchpointCommand.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
+// C++ Includes
+
+
+#include "CommandObjectWatchpointCommand.h"
+#include "CommandObjectWatchpoint.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/State.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointCommandAdd
+//-------------------------------------------------------------------------
+
+
+class CommandObjectWatchpointCommandAdd : public CommandObjectParsed
+{
+public:
+
+ CommandObjectWatchpointCommandAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "add",
+ "Add a set of commands to a watchpoint, to be executed whenever the watchpoint is hit.",
+ NULL),
+ m_options (interpreter)
+ {
+ SetHelpLong (
+"\nGeneral information about entering watchpoint commands \n\
+------------------------------------------------------ \n\
+ \n\
+This command will cause you to be prompted to enter the command or set \n\
+of commands you wish to be executed when the specified watchpoint is \n\
+hit. You will be told to enter your command(s), and will see a '> ' \n\
+prompt. Because you can enter one or many commands to be executed when \n\
+a watchpoint is hit, you will continue to be prompted after each \n\
+new-line that you enter, until you enter the word 'DONE', which will \n\
+cause the commands you have entered to be stored with the watchpoint \n\
+and executed when the watchpoint is hit. \n\
+ \n\
+Syntax checking is not necessarily done when watchpoint commands are \n\
+entered. An improperly written watchpoint command will attempt to get \n\
+executed when the watchpoint gets hit, and usually silently fail. If \n\
+your watchpoint command does not appear to be getting executed, go \n\
+back and check your syntax. \n\
+ \n\
+ \n\
+Special information about PYTHON watchpoint commands \n\
+---------------------------------------------------- \n\
+ \n\
+You may enter either one line of Python or multiple lines of Python \n\
+(including defining whole functions, if desired). If you enter a \n\
+single line of Python, that will be passed to the Python interpreter \n\
+'as is' when the watchpoint gets hit. If you enter function \n\
+definitions, they will be passed to the Python interpreter as soon as \n\
+you finish entering the watchpoint command, and they can be called \n\
+later (don't forget to add calls to them, if you want them called when \n\
+the watchpoint is hit). If you enter multiple lines of Python that \n\
+are not function definitions, they will be collected into a new, \n\
+automatically generated Python function, and a call to the newly \n\
+generated function will be attached to the watchpoint. \n\
+ \n\
+This auto-generated function is passed in two arguments: \n\
+ \n\
+ frame: an SBFrame object representing the frame which hit the watchpoint. \n\
+ From the frame you can get back to the thread and process. \n\
+ wp: the watchpoint that was hit. \n\
+ \n\
+Important Note: Because loose Python code gets collected into functions, \n\
+if you want to access global variables in the 'loose' code, you need to \n\
+specify that they are global, using the 'global' keyword. Be sure to \n\
+use correct Python syntax, including indentation, when entering Python \n\
+watchpoint commands. \n\
+ \n\
+As a third option, you can pass the name of an already existing Python function \n\
+and that function will be attached to the watchpoint. It will get passed the \n\
+frame and wp_loc arguments mentioned above. \n\
+ \n\
+Example Python one-line watchpoint command: \n\
+ \n\
+(lldb) watchpoint command add -s python 1 \n\
+Enter your Python command(s). Type 'DONE' to end. \n\
+> print \"Hit this watchpoint!\" \n\
+> DONE \n\
+ \n\
+As a convenience, this also works for a short Python one-liner: \n\
+(lldb) watchpoint command add -s python 1 -o \"import time; print time.asctime()\" \n\
+(lldb) run \n\
+Launching '.../a.out' (x86_64) \n\
+(lldb) Fri Sep 10 12:17:45 2010 \n\
+Process 21778 Stopped \n\
+* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread \n\
+ 36 \n\
+ 37 int c(int val)\n\
+ 38 {\n\
+ 39 -> return val + 3;\n\
+ 40 }\n\
+ 41 \n\
+ 42 int main (int argc, char const *argv[])\n\
+(lldb) \n\
+ \n\
+Example multiple line Python watchpoint command, using function definition: \n\
+ \n\
+(lldb) watchpoint command add -s python 1 \n\
+Enter your Python command(s). Type 'DONE' to end. \n\
+> def watchpoint_output (wp_no): \n\
+> out_string = \"Hit watchpoint number \" + repr (wp_no) \n\
+> print out_string \n\
+> return True \n\
+> watchpoint_output (1) \n\
+> DONE \n\
+ \n\
+ \n\
+Example multiple line Python watchpoint command, using 'loose' Python: \n\
+ \n\
+(lldb) watchpoint command add -s p 1 \n\
+Enter your Python command(s). Type 'DONE' to end. \n\
+> global wp_count \n\
+> wp_count = wp_count + 1 \n\
+> print \"Hit this watchpoint \" + repr(wp_count) + \" times!\" \n\
+> DONE \n\
+ \n\
+In this case, since there is a reference to a global variable, \n\
+'wp_count', you will also need to make sure 'wp_count' exists and is \n\
+initialized: \n\
+ \n\
+(lldb) script \n\
+>>> wp_count = 0 \n\
+>>> quit() \n\
+ \n\
+(lldb) \n\
+ \n\
+ \n\
+Final Note: If you get a warning that no watchpoint command was generated, \n\
+but you did not get any syntax errors, you probably forgot to add a call \n\
+to your functions. \n\
+ \n\
+Special information about debugger command watchpoint commands \n\
+-------------------------------------------------------------- \n\
+ \n\
+You may enter any debugger command, exactly as you would at the \n\
+debugger prompt. You may enter as many debugger commands as you like, \n\
+but do NOT enter more than one command per line. \n" );
+
+ CommandArgumentEntry arg;
+ CommandArgumentData wp_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ wp_id_arg.arg_type = eArgTypeWatchpointID;
+ wp_id_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (wp_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectWatchpointCommandAdd () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ void
+ CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options,
+ CommandReturnObject &result)
+ {
+ InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
+ std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
+ if (reader_sp && data_ap.get())
+ {
+ BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
+ wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp);
+
+ Error err (reader_sp->Initialize (CommandObjectWatchpointCommandAdd::GenerateWatchpointCommandCallback,
+ wp_options, // callback_data
+ eInputReaderGranularityLine, // token size, to pass to callback function
+ "DONE", // end token
+ "> ", // prompt
+ true)); // echo input
+ if (err.Success())
+ {
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ }
+
+ /// Set a one-liner as the callback for the watchpoint.
+ void
+ 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);
+ data_ap->stop_on_error = m_options.m_stop_on_error;
+
+ BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
+ wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp);
+
+ return;
+ }
+
+ static size_t
+ GenerateWatchpointCommandCallback (void *callback_data,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ 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:
+ if (reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderGotToken:
+ if (bytes && bytes_len && callback_data)
+ {
+ WatchpointOptions *wp_options = (WatchpointOptions *) callback_data;
+ if (wp_options)
+ {
+ Baton *wp_options_baton = wp_options->GetBaton();
+ if (wp_options_baton)
+ ((WatchpointOptions::CommandData *)wp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
+ }
+ }
+ if (!reader.IsDone() && reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ break;
+
+ case eInputReaderInterrupt:
+ {
+ // Finish, and cancel the watchpoint command.
+ reader.SetIsDone (true);
+ WatchpointOptions *wp_options = (WatchpointOptions *) callback_data;
+ if (wp_options)
+ {
+ Baton *wp_options_baton = wp_options->GetBaton ();
+ if (wp_options_baton)
+ {
+ ((WatchpointOptions::CommandData *) wp_options_baton->m_data)->user_source.Clear();
+ ((WatchpointOptions::CommandData *) wp_options_baton->m_data)->script_source.clear();
+ }
+ }
+ if (!batch_mode)
+ {
+ out_stream->Printf ("Warning: No command attached to watchpoint.\n");
+ out_stream->Flush();
+ }
+ }
+ break;
+
+ case eInputReaderEndOfFile:
+ reader.SetIsDone (true);
+ break;
+
+ case eInputReaderDone:
+ break;
+ }
+
+ return bytes_len;
+ }
+
+ static bool
+ WatchpointOptionsCallbackFunction (void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t watch_id)
+ {
+ bool ret_value = true;
+ if (baton == NULL)
+ return true;
+
+
+ WatchpointOptions::CommandData *data = (WatchpointOptions::CommandData *) baton;
+ StringList &commands = data->user_source;
+
+ if (commands.GetSize() > 0)
+ {
+ ExecutionContext exe_ctx (context->exe_ctx_ref);
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ CommandReturnObject result;
+ Debugger &debugger = target->GetDebugger();
+ // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously
+ // if the debugger is set up that way.
+
+ StreamSP output_stream (debugger.GetAsyncOutputStream());
+ StreamSP error_stream (debugger.GetAsyncErrorStream());
+ result.SetImmediateOutputStream (output_stream);
+ result.SetImmediateErrorStream (error_stream);
+
+ bool stop_on_continue = true;
+ bool echo_commands = false;
+ bool print_results = true;
+
+ debugger.GetCommandInterpreter().HandleCommands (commands,
+ &exe_ctx,
+ stop_on_continue,
+ data->stop_on_error,
+ echo_commands,
+ print_results,
+ eLazyBoolNo,
+ result);
+ result.GetImmediateOutputStream()->Flush();
+ result.GetImmediateErrorStream()->Flush();
+ }
+ }
+ return ret_value;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_use_commands (false),
+ m_use_script_language (false),
+ m_script_language (eScriptLanguageNone),
+ m_use_one_liner (false),
+ m_one_liner(),
+ m_function_name()
+ {
+ }
+
+ virtual
+ ~CommandOptions () {}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'o':
+ m_use_one_liner = true;
+ m_one_liner = option_arg;
+ break;
+
+ case 's':
+ m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg,
+ g_option_table[option_idx].enum_values,
+ eScriptLanguageNone,
+ error);
+
+ if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault)
+ {
+ m_use_script_language = true;
+ }
+ else
+ {
+ m_use_script_language = false;
+ }
+ break;
+
+ case 'e':
+ {
+ bool success = false;
+ m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg);
+ }
+ break;
+
+ case 'F':
+ {
+ m_use_one_liner = false;
+ m_use_script_language = true;
+ m_function_name.assign(option_arg);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return error;
+ }
+ void
+ OptionParsingStarting ()
+ {
+ m_use_commands = true;
+ m_use_script_language = false;
+ m_script_language = eScriptLanguageNone;
+
+ m_use_one_liner = false;
+ m_stop_on_error = true;
+ m_one_liner.clear();
+ m_function_name.clear();
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_use_commands;
+ bool m_use_script_language;
+ lldb::ScriptLanguage m_script_language;
+
+ // Instance variables to hold the values for one_liner options.
+ bool m_use_one_liner;
+ std::string m_one_liner;
+ bool m_stop_on_error;
+ std::string m_function_name;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+ if (target == NULL)
+ {
+ result.AppendError ("There is not a current executable; there are no watchpoints to which to add commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError ("No watchpoints exist to have commands added");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_use_script_language == false && m_options.m_function_name.size())
+ {
+ result.AppendError ("need to enable scripting to have a function run as a watchpoint command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ std::vector<uint32_t> valid_wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ const size_t count = valid_wp_ids.size();
+ for (size_t i = 0; i < count; ++i)
+ {
+ uint32_t cur_wp_id = valid_wp_ids.at (i);
+ if (cur_wp_id != LLDB_INVALID_WATCH_ID)
+ {
+ Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
+ // Sanity check wp first.
+ if (wp == NULL) continue;
+
+ WatchpointOptions *wp_options = wp->GetOptions();
+ // Skip this watchpoint if wp_options is not good.
+ if (wp_options == NULL) continue;
+
+ // If we are using script language, get the script interpreter
+ // in order to set or collect command callback. Otherwise, call
+ // the methods associated with this object.
+ if (m_options.m_use_script_language)
+ {
+ // Special handling for one-liner specified inline.
+ if (m_options.m_use_one_liner)
+ {
+ m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
+ m_options.m_one_liner.c_str());
+ }
+ // Special handling for using a Python function by name
+ // instead of extending the watchpoint callback data structures, we just automatize
+ // what the user would do manually: make their watchpoint command be a function call
+ else if (m_options.m_function_name.size())
+ {
+ std::string oneliner(m_options.m_function_name);
+ oneliner += "(frame, wp, internal_dict)";
+ m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
+ oneliner.c_str());
+ }
+ else
+ {
+ m_interpreter.GetScriptInterpreter()->CollectDataForWatchpointCommandCallback (wp_options,
+ result);
+ }
+ }
+ else
+ {
+ // Special handling for one-liner specified inline.
+ if (m_options.m_use_one_liner)
+ SetWatchpointCommandCallback (wp_options,
+ m_options.m_one_liner.c_str());
+ else
+ CollectDataForWatchpointCommandCallback (wp_options,
+ result);
+ }
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+ static const char *g_reader_instructions;
+
+};
+
+const char *
+CommandObjectWatchpointCommandAdd::g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.";
+
+// FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting
+// language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper.
+
+static OptionEnumValueElement
+g_script_option_enumeration[4] =
+{
+ { eScriptLanguageNone, "command", "Commands are in the lldb command interpreter language"},
+ { eScriptLanguagePython, "python", "Commands are in the Python language."},
+ { eSortOrderByName, "default-script", "Commands are in the default scripting language."},
+ { 0, NULL, NULL }
+};
+
+OptionDefinition
+CommandObjectWatchpointCommandAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "one-liner", 'o', required_argument, NULL, 0, eArgTypeOneLiner,
+ "Specify a one-line watchpoint command inline. Be sure to surround it with quotes." },
+
+ { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', required_argument, NULL, 0, eArgTypeBoolean,
+ "Specify whether watchpoint command execution should terminate on error." },
+
+ { LLDB_OPT_SET_ALL, false, "script-type", 's', required_argument, g_script_option_enumeration, 0, eArgTypeNone,
+ "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
+
+ { LLDB_OPT_SET_2, false, "python-function", 'F', required_argument, NULL, 0, eArgTypePythonFunction,
+ "Give the name of a Python function to run as command for this watchpoint. Be sure to give a module name if appropriate."},
+
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointCommandDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectWatchpointCommandDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectWatchpointCommandDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "delete",
+ "Delete the set of commands from a watchpoint.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData wp_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ wp_id_arg.arg_type = eArgTypeWatchpointID;
+ wp_id_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (wp_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ virtual
+ ~CommandObjectWatchpointCommandDelete () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+ if (target == NULL)
+ {
+ result.AppendError ("There is not a current executable; there are no watchpoints from which to delete commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError ("No watchpoints exist to have commands deleted");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ result.AppendError ("No watchpoint specified from which to delete the commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ std::vector<uint32_t> valid_wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ const size_t count = valid_wp_ids.size();
+ for (size_t i = 0; i < count; ++i)
+ {
+ uint32_t cur_wp_id = valid_wp_ids.at (i);
+ if (cur_wp_id != LLDB_INVALID_WATCH_ID)
+ {
+ Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
+ if (wp)
+ wp->ClearCallback();
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n",
+ cur_wp_id);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointCommandList
+//-------------------------------------------------------------------------
+
+class CommandObjectWatchpointCommandList : public CommandObjectParsed
+{
+public:
+ CommandObjectWatchpointCommandList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "list",
+ "List the script or set of commands to be executed when the watchpoint is hit.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData wp_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ wp_id_arg.arg_type = eArgTypeWatchpointID;
+ wp_id_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (wp_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectWatchpointCommandList () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+ if (target == NULL)
+ {
+ result.AppendError ("There is not a current executable; there are no watchpoints for which to list commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError ("No watchpoints exist for which to list commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ result.AppendError ("No watchpoint specified for which to list the commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ std::vector<uint32_t> valid_wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ const size_t count = valid_wp_ids.size();
+ for (size_t i = 0; i < count; ++i)
+ {
+ uint32_t cur_wp_id = valid_wp_ids.at (i);
+ if (cur_wp_id != LLDB_INVALID_WATCH_ID)
+ {
+ Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
+
+ if (wp)
+ {
+ const WatchpointOptions *wp_options = wp->GetOptions();
+ if (wp_options)
+ {
+ // Get the callback baton associated with the current watchpoint.
+ const Baton *baton = wp_options->GetBaton();
+ if (baton)
+ {
+ result.GetOutputStream().Printf ("Watchpoint %u:\n", cur_wp_id);
+ result.GetOutputStream().IndentMore ();
+ baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
+ result.GetOutputStream().IndentLess ();
+ }
+ else
+ {
+ result.AppendMessageWithFormat ("Watchpoint %u does not have an associated command.\n",
+ cur_wp_id);
+ }
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointCommand
+//-------------------------------------------------------------------------
+
+CommandObjectWatchpointCommand::CommandObjectWatchpointCommand (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "command",
+ "A set of commands for adding, removing and examining bits of code to be executed when the watchpoint is hit (watchpoint 'commmands').",
+ "command <sub-command> [<sub-command-options>] <watchpoint-id>")
+{
+ CommandObjectSP add_command_object (new CommandObjectWatchpointCommandAdd (interpreter));
+ CommandObjectSP delete_command_object (new CommandObjectWatchpointCommandDelete (interpreter));
+ CommandObjectSP list_command_object (new CommandObjectWatchpointCommandList (interpreter));
+
+ add_command_object->SetCommandName ("watchpoint command add");
+ delete_command_object->SetCommandName ("watchpoint command delete");
+ list_command_object->SetCommandName ("watchpoint command list");
+
+ LoadSubCommand ("add", add_command_object);
+ LoadSubCommand ("delete", delete_command_object);
+ LoadSubCommand ("list", list_command_object);
+}
+
+CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand ()
+{
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.h
new file mode 100644
index 0000000..c2faf71
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.h
@@ -0,0 +1,46 @@
+//===-- CommandObjectWatchpointCommand.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_CommandObjectWatchpointCommand_h_
+#define liblldb_CommandObjectWatchpointCommand_h_
+
+// C Includes
+// C++ Includes
+
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-types.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordWatchpoint
+//-------------------------------------------------------------------------
+
+class CommandObjectWatchpointCommand : public CommandObjectMultiword
+{
+public:
+ CommandObjectWatchpointCommand (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectWatchpointCommand ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectWatchpointCommand_h_
OpenPOWER on IntegriCloud