Python summary strings:
- you can use a Python script to write a summary string for data-types, in one of
three ways:
-P option and typing the script a line at a time
-s option and passing a one-line Python script
-F option and passing the name of a Python function
these options all work for the "type summary add" command
your Python code (if provided through -P or -s) is wrapped in a function
that accepts two parameters: valobj (a ValueObject) and dict (an LLDB
internal dictionary object). if you use -F and give a function name,
you're expected to define the function on your own and with the right
prototype. your function, however defined, must return a Python string
- test case for the Python summary feature
- a few quirks:
Python summaries cannot have names, and cannot use regex as type names
both issues will be fixed ASAP
major redesign of type summary code:
- type summary working with strings and type summary working with Python code
are two classes, with a common base class SummaryFormat
- SummaryFormat classes now are able to actively format objects rather than
just aggregating data
- cleaner code to print descriptions for summaries
the public API now exports a method to easily navigate a ValueObject hierarchy
New InputReaderEZ and PriorityPointerPair classes
Several minor fixes and improvements
git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@135238 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/lldb/API/SBValue.h b/include/lldb/API/SBValue.h
index 40a4612..9fce5bc 100644
--- a/include/lldb/API/SBValue.h
+++ b/include/lldb/API/SBValue.h
@@ -167,6 +167,10 @@
// classes.
lldb::SBValue
GetChildMemberWithName (const char *name, lldb::DynamicValueType use_dynamic);
+
+ // Expands nested expressions like .a->b[0].c[1]->d
+ lldb::SBValue
+ GetValueForExpressionPath(const char* expr_path);
uint32_t
GetNumChildren ();
@@ -190,12 +194,12 @@
bool
GetExpressionPath (lldb::SBStream &description, bool qualify_cxx_base_classes);
+ SBValue (const lldb::ValueObjectSP &value_sp);
+
protected:
friend class SBValueList;
friend class SBFrame;
- SBValue (const lldb::ValueObjectSP &value_sp);
-
#ifndef SWIG
// Mimic shared pointer...
diff --git a/include/lldb/Core/Debugger.h b/include/lldb/Core/Debugger.h
index f43b842..ea9a648 100644
--- a/include/lldb/Core/Debugger.h
+++ b/include/lldb/Core/Debugger.h
@@ -576,8 +576,6 @@
static uint32_t
GetCount();
};
-
-
};
} // namespace lldb_private
diff --git a/include/lldb/Core/Error.h b/include/lldb/Core/Error.h
index a36d842..a0476c8 100644
--- a/include/lldb/Core/Error.h
+++ b/include/lldb/Core/Error.h
@@ -69,6 +69,9 @@
explicit
Error (ValueType err, lldb::ErrorType type = lldb::eErrorTypeGeneric);
+ explicit
+ Error (const char* err_str);
+
Error (const Error &rhs);
//------------------------------------------------------------------
/// Assignment operator.
diff --git a/include/lldb/Core/FormatManager.h b/include/lldb/Core/FormatManager.h
index f1bd52c..1fc4756 100644
--- a/include/lldb/Core/FormatManager.h
+++ b/include/lldb/Core/FormatManager.h
@@ -50,8 +50,10 @@
#include "lldb/Core/UserID.h"
#include "lldb/Core/UserSettingsController.h"
#include "lldb/Core/ValueObject.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Platform.h"
+#include "lldb/Target/StackFrame.h"
#include "lldb/Target/TargetList.h"
namespace lldb_private {
@@ -67,8 +69,263 @@
};
+struct ValueFormat
+{
+ bool m_cascades;
+ bool m_skip_pointers;
+ bool m_skip_references;
+ lldb::Format m_format;
+ ValueFormat (lldb::Format f = lldb::eFormatInvalid,
+ bool casc = false,
+ bool skipptr = false,
+ bool skipref = false) :
+ m_cascades(casc),
+ m_skip_pointers(skipptr),
+ m_skip_references(skipref),
+ m_format (f)
+ {
+ }
+
+ typedef lldb::SharedPtr<ValueFormat>::Type SharedPointer;
+ typedef bool(*ValueCallback)(void*, const char*, const ValueFormat::SharedPointer&);
+
+ ~ValueFormat()
+ {
+ }
+
+ bool
+ Cascades()
+ {
+ return m_cascades;
+ }
+ bool
+ SkipsPointers()
+ {
+ return m_skip_pointers;
+ }
+ bool
+ SkipsReferences()
+ {
+ return m_skip_references;
+ }
+
+ lldb::Format
+ GetFormat()
+ {
+ return m_format;
+ }
+
+ std::string
+ FormatObject(lldb::ValueObjectSP object)
+ {
+ if (!object.get())
+ return "NULL";
+
+ StreamString sstr;
+
+ if (ClangASTType::DumpTypeValue (object->GetClangAST(), // The clang AST
+ object->GetClangType(), // The clang type to display
+ &sstr,
+ m_format, // Format to display this type with
+ object->GetDataExtractor(), // Data to extract from
+ 0, // Byte offset into "data"
+ object->GetByteSize(), // Byte size of item in "data"
+ object->GetBitfieldBitSize(), // Bitfield bit size
+ object->GetBitfieldBitOffset())) // Bitfield bit offset
+ return (sstr.GetString());
+ else
+ {
+ return ("unsufficient data for value");
+ }
+
+ }
+
+};
+
struct SummaryFormat
{
+ bool m_cascades;
+ bool m_skip_pointers;
+ bool m_skip_references;
+ bool m_dont_show_children;
+ bool m_dont_show_value;
+ bool m_show_members_oneliner;
+
+ SummaryFormat(bool casc = false,
+ bool skipptr = false,
+ bool skipref = false,
+ bool nochildren = true,
+ bool novalue = true,
+ bool oneliner = false) :
+ m_cascades(casc),
+ m_skip_pointers(skipptr),
+ m_skip_references(skipref),
+ m_dont_show_children(nochildren),
+ m_dont_show_value(novalue),
+ m_show_members_oneliner(oneliner)
+ {
+ }
+
+ bool
+ Cascades()
+ {
+ return m_cascades;
+ }
+ bool
+ SkipsPointers()
+ {
+ return m_skip_pointers;
+ }
+ bool
+ SkipsReferences()
+ {
+ return m_skip_references;
+ }
+
+ bool
+ DoesPrintChildren() const
+ {
+ return !m_dont_show_children;
+ }
+
+ bool
+ DoesPrintValue() const
+ {
+ return !m_dont_show_value;
+ }
+
+ bool
+ IsOneliner() const
+ {
+ return m_show_members_oneliner;
+ }
+
+ virtual
+ ~SummaryFormat()
+ {
+ }
+
+ virtual std::string
+ FormatObject(lldb::ValueObjectSP object) = 0;
+
+ virtual std::string
+ GetDescription() = 0;
+
+ typedef lldb::SharedPtr<SummaryFormat>::Type SharedPointer;
+ typedef bool(*SummaryCallback)(void*, const char*, const SummaryFormat::SharedPointer&);
+ typedef bool(*RegexSummaryCallback)(void*, lldb::RegularExpressionSP, const SummaryFormat::SharedPointer&);
+
+};
+
+// simple string-based summaries, using ${var to show data
+struct StringSummaryFormat : public SummaryFormat
+{
+ std::string m_format;
+
+ StringSummaryFormat(bool casc = false,
+ bool skipptr = false,
+ bool skipref = false,
+ bool nochildren = true,
+ bool novalue = true,
+ bool oneliner = false,
+ std::string f = "") :
+ SummaryFormat(casc,skipptr,skipref,nochildren,novalue,oneliner),
+ m_format(f)
+ {
+ }
+
+ std::string
+ GetFormat()
+ {
+ return m_format;
+ }
+
+ virtual
+ ~StringSummaryFormat()
+ {
+ }
+
+ virtual std::string
+ FormatObject(lldb::ValueObjectSP object);
+
+ virtual std::string
+ GetDescription()
+ {
+ StreamString sstr;
+ sstr.Printf ("`%s`%s%s%s%s%s%s\n", m_format.c_str(),
+ m_cascades ? "" : " (not cascading)",
+ m_dont_show_children ? "" : " (show children)",
+ m_dont_show_value ? " (hide value)" : "",
+ m_show_members_oneliner ? " (one-line printout)" : "",
+ m_skip_pointers ? " (skip pointers)" : "",
+ m_skip_references ? " (skip references)" : "");
+ return sstr.GetString();
+ }
+
+};
+
+// Python-based summaries, running script code to show data
+struct ScriptSummaryFormat : public SummaryFormat
+{
+ std::string m_function_name;
+ std::string m_python_script;
+
+ ScriptSummaryFormat(bool casc = false,
+ bool skipptr = false,
+ bool skipref = false,
+ bool nochildren = true,
+ bool novalue = true,
+ bool oneliner = false,
+ std::string fname = "",
+ std::string pscri = "") :
+ SummaryFormat(casc,skipptr,skipref,nochildren,novalue,oneliner),
+ m_function_name(fname),
+ m_python_script(pscri)
+ {
+ }
+
+ std::string
+ GetFunctionName()
+ {
+ return m_function_name;
+ }
+
+ std::string
+ GetPythonScript()
+ {
+ return m_python_script;
+ }
+
+ virtual
+ ~ScriptSummaryFormat()
+ {
+ }
+
+ virtual std::string
+ FormatObject(lldb::ValueObjectSP object)
+ {
+ return std::string(ScriptInterpreterPython::CallPythonScriptFunction(m_function_name.c_str(),
+ object).c_str());
+ }
+
+ virtual std::string
+ GetDescription()
+ {
+ StreamString sstr;
+ sstr.Printf ("%s%s%s\n%s\n", m_cascades ? "" : " (not cascading)",
+ m_skip_pointers ? " (skip pointers)" : "",
+ m_skip_references ? " (skip references)" : "",
+ m_python_script.c_str());
+ return sstr.GetString();
+
+ }
+
+ typedef lldb::SharedPtr<ScriptSummaryFormat>::Type SharedPointer;
+
+};
+
+/*struct SummaryFormat
+{
std::string m_format;
bool m_dont_show_children;
bool m_dont_show_value;
@@ -116,32 +373,35 @@
typedef bool(*RegexSummaryCallback)(void*, lldb::RegularExpressionSP, const SummaryFormat::SharedPointer&);
};
-
-struct ValueFormat
+
+struct ScriptFormat
{
- lldb::Format m_format;
+ std::string m_function_name;
+ std::string m_python_script;
bool m_cascades;
bool m_skip_references;
bool m_skip_pointers;
- ValueFormat (lldb::Format f = lldb::eFormatInvalid,
- bool c = false,
- bool skipptr = false,
- bool skipref = false) :
- m_format (f),
+ ScriptFormat (std::string n,
+ std::string s = "",
+ bool c = false,
+ bool skipptr = false,
+ bool skipref = false) :
+ m_function_name (n),
+ m_python_script(s),
m_cascades (c),
m_skip_references(skipref),
m_skip_pointers(skipptr)
{
}
- typedef lldb::SharedPtr<ValueFormat>::Type SharedPointer;
- typedef bool(*ValueCallback)(void*, const char*, const ValueFormat::SharedPointer&);
+ typedef lldb::SharedPtr<ScriptFormat>::Type SharedPointer;
+ typedef bool(*ScriptCallback)(void*, const char*, const ScriptFormat::SharedPointer&);
- ~ValueFormat()
+ ~ScriptFormat()
{
}
-};
+};*/
template<typename KeyType, typename ValueType>
class FormatNavigator;
@@ -457,11 +717,13 @@
typedef FormatNavigator<const char*, ValueFormat> ValueNavigator;
typedef FormatNavigator<const char*, SummaryFormat> SummaryNavigator;
typedef FormatNavigator<lldb::RegularExpressionSP, SummaryFormat> RegexSummaryNavigator;
+ typedef FormatNavigator<const char*, SummaryFormat> ScriptNavigator;
typedef ValueNavigator::MapType ValueMap;
typedef SummaryNavigator::MapType SummaryMap;
typedef RegexSummaryNavigator::MapType RegexSummaryMap;
typedef FormatMap<const char*, SummaryFormat> NamedSummariesMap;
+ typedef ScriptNavigator::MapType ScriptMap;
ValueNavigator m_value_nav;
SummaryNavigator m_summary_nav;
@@ -469,6 +731,8 @@
NamedSummariesMap m_named_summaries_map;
+ ScriptNavigator m_script_nav;
+
uint32_t m_last_revision;
public:
@@ -478,6 +742,7 @@
m_summary_nav(this),
m_regex_summary_nav(this),
m_named_summaries_map(this),
+ m_script_nav(this),
m_last_revision(0)
{
}
@@ -487,6 +752,7 @@
SummaryNavigator& Summary() { return m_summary_nav; }
RegexSummaryNavigator& RegexSummary() { return m_regex_summary_nav; }
NamedSummariesMap& NamedSummary() { return m_named_summaries_map; }
+ ScriptNavigator& Script() { return m_script_nav; }
static bool
GetFormatFromCString (const char *format_cstr,
diff --git a/include/lldb/Core/InputReader.h b/include/lldb/Core/InputReader.h
index c1658a2..e1cc6aa 100644
--- a/include/lldb/Core/InputReader.h
+++ b/include/lldb/Core/InputReader.h
@@ -12,7 +12,7 @@
#include "lldb/lldb-public.h"
#include "lldb/lldb-enumerations.h"
-#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Error.h"
#include "lldb/Host/Predicate.h"
@@ -27,6 +27,31 @@
lldb::InputReaderAction notification,
const char *bytes,
size_t bytes_len);
+
+ struct HandlerData
+ {
+ InputReader& reader;
+ const char *bytes;
+ size_t bytes_len;
+ void* baton;
+
+ HandlerData(InputReader& r,
+ const char* b,
+ size_t l,
+ void* t) :
+ reader(r),
+ bytes(b),
+ bytes_len(l),
+ baton(t)
+ {
+ }
+
+ lldb::StreamSP
+ GetOutStream();
+
+ bool
+ GetBatchMode();
+ };
InputReader (Debugger &debugger);
@@ -41,6 +66,41 @@
const char *prompt,
bool echo);
+ virtual Error Initialize(void* baton,
+ lldb::InputReaderGranularity token_size = lldb::eInputReaderGranularityLine,
+ const char* end_token = "DONE",
+ const char *prompt = "> ",
+ bool echo = true)
+ {
+ return Error("unimplemented");
+ }
+
+ // to use these handlers instead of the Callback function, you must subclass
+ // InputReaderEZ, and redefine the handlers for the events you care about
+ virtual void
+ ActivateHandler(HandlerData&) {}
+
+ virtual void
+ DeactivateHandler(HandlerData&) {}
+
+ virtual void
+ ReactivateHandler(HandlerData&) {}
+
+ virtual void
+ AsynchronousOutputWrittenHandler(HandlerData&) {}
+
+ virtual void
+ GotTokenHandler(HandlerData&) {}
+
+ virtual void
+ InterruptHandler(HandlerData&) {}
+
+ virtual void
+ EOFHandler(HandlerData&) {}
+
+ virtual void
+ DoneHandler(HandlerData&) {}
+
bool
IsDone () const
{
diff --git a/include/lldb/Core/InputReaderEZ.h b/include/lldb/Core/InputReaderEZ.h
new file mode 100644
index 0000000..95f6af9
--- /dev/null
+++ b/include/lldb/Core/InputReaderEZ.h
@@ -0,0 +1,81 @@
+//===-- InputReaderEZ.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_InputReaderEZ_h_
+#define liblldb_InputReaderEZ_h_
+
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Host/Predicate.h"
+
+
+namespace lldb_private {
+
+class InputReaderEZ : public InputReader
+{
+
+private:
+
+ static size_t Callback_Impl(void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+public:
+
+ InputReaderEZ (Debugger &debugger) :
+ InputReader(debugger)
+ {}
+
+ virtual
+ ~InputReaderEZ ();
+
+ virtual Error Initialize(void* baton,
+ lldb::InputReaderGranularity token_size = lldb::eInputReaderGranularityLine,
+ const char* end_token = "DONE",
+ const char *prompt = "> ",
+ bool echo = true);
+
+ virtual void
+ ActivateHandler(HandlerData&) {}
+
+ virtual void
+ DeactivateHandler(HandlerData&) {}
+
+ virtual void
+ ReactivateHandler(HandlerData&) {}
+
+ virtual void
+ AsynchronousOutputWrittenHandler(HandlerData&) {}
+
+ virtual void
+ GotTokenHandler(HandlerData&) {}
+
+ virtual void
+ InterruptHandler(HandlerData&) {}
+
+ virtual void
+ EOFHandler(HandlerData&) {}
+
+ virtual void
+ DoneHandler(HandlerData&) {}
+
+protected:
+ friend class Debugger;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (InputReaderEZ);
+
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_InputReaderEZ_h_
diff --git a/include/lldb/Core/StringList.h b/include/lldb/Core/StringList.h
index b080919..c4edb82 100644
--- a/include/lldb/Core/StringList.h
+++ b/include/lldb/Core/StringList.h
@@ -68,7 +68,17 @@
size_t
SplitIntoLines (const char *lines, size_t len);
+
+ std::string
+ CopyList(const char* item_preamble = NULL,
+ const char* items_sep = "\n");
+
+ StringList&
+ operator << (const char* str);
+ StringList&
+ operator << (StringList strings);
+
private:
STLStringArray m_strings;
diff --git a/include/lldb/Core/ValueObject.h b/include/lldb/Core/ValueObject.h
index 87f41d9..d7e39de 100644
--- a/include/lldb/Core/ValueObject.h
+++ b/include/lldb/Core/ValueObject.h
@@ -27,6 +27,7 @@
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/StackID.h"
+#include "lldb/Utility/PriorityPointerPair.h"
#include "lldb/Utility/SharedCluster.h"
namespace lldb_private {
@@ -75,7 +76,8 @@
{
eDisplayValue = 1,
eDisplaySummary,
- eDisplayLanguageSpecific
+ eDisplayLanguageSpecific,
+ eDisplayLocation
};
enum ExpressionPathScanEndReason
@@ -731,8 +733,8 @@
lldb::Format m_format;
uint32_t m_last_format_mgr_revision;
lldb::SummaryFormatSP m_last_summary_format;
- lldb::ValueFormatSP m_last_value_format;
lldb::SummaryFormatSP m_forced_summary_format;
+ lldb::ValueFormatSP m_last_value_format;
lldb::user_id_t m_user_id_of_forced_summary;
bool m_value_is_valid:1,
m_value_did_change:1,
@@ -802,6 +804,9 @@
void
SetValueIsValid (bool valid);
+
+ void
+ ClearUserVisibleData();
public:
lldb::addr_t
diff --git a/include/lldb/Interpreter/ScriptInterpreter.h b/include/lldb/Interpreter/ScriptInterpreter.h
index 438222c..38ac00e 100644
--- a/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/include/lldb/Interpreter/ScriptInterpreter.h
@@ -26,6 +26,13 @@
const char *session_dictionary_name,
const lldb::StackFrameSP& frame_sp,
const lldb::BreakpointLocationSP &bp_loc_sp);
+
+ typedef
+
+ typedef std::string (*SWIGPythonTypeScriptCallbackFunction) (const char *python_function_name,
+ const char *session_dictionary_name,
+ const lldb::ValueObjectSP& valobj_sp);
+
typedef enum
{
eCharPtr,
@@ -77,6 +84,25 @@
{
return false;
}
+
+ virtual bool
+ GenerateTypeScriptFunction (StringList &input, StringList &output)
+ {
+ return false;
+ }
+
+ // use this if the function code is just a one-liner script
+ virtual bool
+ GenerateTypeScriptFunction (const char* oneliner, StringList &output)
+ {
+ return false;
+ }
+
+ virtual bool
+ GenerateFunction(std::string& signature, StringList &input, StringList &output)
+ {
+ return false;
+ }
virtual void
CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
@@ -104,7 +130,8 @@
static void
InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
- SWIGBreakpointCallbackFunction python_swig_breakpoint_callback);
+ SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
+ SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback);
static void
TerminateInterpreter ();
diff --git a/include/lldb/Interpreter/ScriptInterpreterPython.h b/include/lldb/Interpreter/ScriptInterpreterPython.h
index 4b1c38d..5d33e79 100644
--- a/include/lldb/Interpreter/ScriptInterpreterPython.h
+++ b/include/lldb/Interpreter/ScriptInterpreterPython.h
@@ -50,6 +50,16 @@
ExportFunctionDefinitionToInterpreter (StringList &function_def);
bool
+ GenerateTypeScriptFunction (StringList &input, StringList &output);
+
+ // use this if the function code is just a one-liner script
+ bool
+ GenerateTypeScriptFunction (const char* oneliner, StringList &output);
+
+ bool
+ GenerateFunction(std::string& signature, StringList &input, StringList &output);
+
+ bool
GenerateBreakpointCommandCallbackData (StringList &input, StringList &output);
static size_t
@@ -64,6 +74,10 @@
StoppointCallbackContext *context,
lldb::user_id_t break_id,
lldb::user_id_t break_loc_id);
+
+ static std::string
+ CallPythonScriptFunction (const char *python_function_name,
+ lldb::ValueObjectSP valobj);
void
CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
@@ -88,7 +102,8 @@
static void
InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
- SWIGBreakpointCallbackFunction python_swig_breakpoint_callback);
+ SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
+ SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback);
protected:
diff --git a/include/lldb/Utility/PriorityPointerPair.h b/include/lldb/Utility/PriorityPointerPair.h
new file mode 100644
index 0000000..949173d
--- /dev/null
+++ b/include/lldb/Utility/PriorityPointerPair.h
@@ -0,0 +1,150 @@
+//===-- PriorityPointerPair.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_PriorityPointerPair_h_
+#define liblldb_PriorityPointerPair_h_
+
+#include "lldb/lldb-public.h"
+#include "lldb/Utility/SharingPtr.h"
+
+namespace lldb_utility {
+
+//----------------------------------------------------------------------
+// A prioritized pair of SharedPtr<T>. One of the two pointers is high
+// priority, the other is low priority.
+// The Get() method always returns high, if *high != NULL,
+// otherwise, low is returned (even if *low == NULL)
+//----------------------------------------------------------------------
+
+template<typename T>
+class PriorityPointerPair
+{
+public:
+
+ typedef T& reference_type;
+ typedef T* pointer_type;
+
+ typedef typename lldb::SharedPtr<T>::Type T_SP;
+
+ PriorityPointerPair() :
+ m_high(),
+ m_low()
+ {}
+
+ PriorityPointerPair(pointer_type high,
+ pointer_type low) :
+ m_high(high),
+ m_low(low)
+ {}
+
+ PriorityPointerPair(pointer_type low) :
+ m_high(),
+ m_low(low)
+ {}
+
+ PriorityPointerPair(T_SP& high,
+ T_SP& low) :
+ m_high(high),
+ m_low(low)
+ {}
+
+ PriorityPointerPair(T_SP& low) :
+ m_high(),
+ m_low(low)
+ {}
+
+ void
+ SwapLow(pointer_type l)
+ {
+ m_low.swap(l);
+ }
+
+ void
+ SwapHigh(pointer_type h)
+ {
+ m_high.swap(h);
+ }
+
+ void
+ SwapLow(T_SP l)
+ {
+ m_low.swap(l);
+ }
+
+ void
+ SwapHigh(T_SP h)
+ {
+ m_high.swap(h);
+ }
+
+ T_SP
+ GetLow()
+ {
+ return m_low;
+ }
+
+ T_SP
+ GetHigh()
+ {
+ return m_high;
+ }
+
+ T_SP
+ Get()
+ {
+ if (m_high.get())
+ return m_high;
+ return m_low;
+ }
+
+ void
+ ResetHigh()
+ {
+ m_high.reset();
+ }
+
+ void
+ ResetLow()
+ {
+ m_low.reset();
+ }
+
+ void
+ Reset()
+ {
+ ResetLow();
+ ResetHigh();
+ }
+
+ reference_type
+ operator*() const
+ {
+ return Get().operator*();
+ }
+
+ pointer_type
+ operator->() const
+ {
+ return Get().operator->();
+ }
+
+ ~PriorityPointerPair();
+
+private:
+
+ T_SP m_high;
+ T_SP m_low;
+
+ DISALLOW_COPY_AND_ASSIGN (PriorityPointerPair);
+
+};
+
+} // namespace lldb_utility
+
+#endif // #ifndef liblldb_PriorityPointerPair_h_
diff --git a/include/lldb/Utility/RefCounter.h b/include/lldb/Utility/RefCounter.h
index 7c3e341..6daed54 100644
--- a/include/lldb/Utility/RefCounter.h
+++ b/include/lldb/Utility/RefCounter.h
@@ -20,8 +20,6 @@
// RefCounter ref(ptr);
// (of course, the pointer is a shared resource, and must be accessible to
// everyone who needs it). Synchronization is handled by RefCounter itself
-// To check if more than 1 RefCounter is attached to the same value, you can
-// either call shared(), or simply cast ref to bool
// The counter is decreased each time a RefCounter to it goes out of scope
//----------------------------------------------------------------------
class RefCounter
diff --git a/include/lldb/lldb-forward-rtti.h b/include/lldb/lldb-forward-rtti.h
index b5a02d6..858e521 100644
--- a/include/lldb/lldb-forward-rtti.h
+++ b/include/lldb/lldb-forward-rtti.h
@@ -56,11 +56,13 @@
typedef SharedPtr<lldb_private::RegularExpression>::Type RegularExpressionSP;
typedef SharedPtr<lldb_private::Section>::Type SectionSP;
typedef SharedPtr<lldb_private::SearchFilter>::Type SearchFilterSP;
+ typedef SharedPtr<lldb_private::ScriptSummaryFormat>::Type ScriptFormatSP;
typedef SharedPtr<lldb_private::StackFrame>::Type StackFrameSP;
typedef SharedPtr<lldb_private::StackFrameList>::Type StackFrameListSP;
typedef SharedPtr<lldb_private::StopInfo>::Type StopInfoSP;
typedef SharedPtr<lldb_private::StoppointLocation>::Type StoppointLocationSP;
typedef SharedPtr<lldb_private::Stream>::Type StreamSP;
+ typedef SharedPtr<lldb_private::StringSummaryFormat>::Type StringSummaryFormatSP;
typedef SharedPtr<lldb_private::SummaryFormat>::Type SummaryFormatSP;
typedef SharedPtr<lldb_private::SymbolFile>::Type SymbolFileSP;
typedef SharedPtr<lldb_private::SymbolContextSpecifier>::Type SymbolContextSpecifierSP;
diff --git a/include/lldb/lldb-forward.h b/include/lldb/lldb-forward.h
index 4b3a97f..9d616d1 100644
--- a/include/lldb/lldb-forward.h
+++ b/include/lldb/lldb-forward.h
@@ -114,6 +114,7 @@
class RegisterValue;
class RegularExpression;
class Scalar;
+class ScriptSummaryFormat;
class ScriptInterpreter;
class ScriptInterpreterPython;
class SearchFilter;
@@ -131,6 +132,7 @@
class StreamFile;
class StreamString;
class StringList;
+class StringSummaryFormat;
class SummaryFormat;
class Symbol;
class SymbolContext;
diff --git a/lldb.xcodeproj/project.pbxproj b/lldb.xcodeproj/project.pbxproj
index 41882a2..47345bf 100644
--- a/lldb.xcodeproj/project.pbxproj
+++ b/lldb.xcodeproj/project.pbxproj
@@ -402,6 +402,7 @@
4CCA645613B40B82003BDF98 /* AppleObjCTrampolineHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CCA644813B40B82003BDF98 /* AppleObjCTrampolineHandler.cpp */; };
4CCA645813B40B82003BDF98 /* AppleThreadPlanStepThroughObjCTrampoline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CCA644A13B40B82003BDF98 /* AppleThreadPlanStepThroughObjCTrampoline.cpp */; };
4CD0BD0F134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */; };
+ 94031A9E13CF486700DCFF3C /* InputReaderEZ.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94031A9D13CF486600DCFF3C /* InputReaderEZ.cpp */; };
9415F61813B2C0EF00A52B36 /* FormatManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9415F61713B2C0EF00A52B36 /* FormatManager.cpp */; };
94611EB213CCA4A4003A22AF /* RefCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94611EB113CCA4A4003A22AF /* RefCounter.cpp */; };
9463D4CD13B1798800C230D4 /* CommandObjectType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9463D4CC13B1798800C230D4 /* CommandObjectType.cpp */; };
@@ -631,8 +632,8 @@
261B5A5311C3F2AD00AABD0A /* SharingPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SharingPtr.h; path = include/lldb/Utility/SharingPtr.h; sourceTree = "<group>"; };
26217930133BC8640083B112 /* lldb-private-types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "lldb-private-types.h"; path = "include/lldb/lldb-private-types.h"; sourceTree = "<group>"; };
26217932133BCB850083B112 /* lldb-private-enumerations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "lldb-private-enumerations.h"; path = "include/lldb/lldb-private-enumerations.h"; sourceTree = "<group>"; };
- 263664921140A4930075843B /* Debugger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Debugger.cpp; path = source/Core/Debugger.cpp; sourceTree = "<group>"; };
- 263664941140A4C10075843B /* Debugger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Debugger.h; path = include/lldb/Core/Debugger.h; sourceTree = "<group>"; };
+ 263664921140A4930075843B /* Debugger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = Debugger.cpp; path = source/Core/Debugger.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+ 263664941140A4C10075843B /* Debugger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = Debugger.h; path = include/lldb/Core/Debugger.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
26368A3B126B697600E8659F /* darwin-debug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "darwin-debug.cpp"; path = "tools/darwin-debug/darwin-debug.cpp"; sourceTree = "<group>"; };
263E949D13661AE400E7D1CE /* UnwindAssembly-x86.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "UnwindAssembly-x86.cpp"; sourceTree = "<group>"; };
263E949E13661AE400E7D1CE /* UnwindAssembly-x86.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UnwindAssembly-x86.h"; sourceTree = "<group>"; };
@@ -677,7 +678,7 @@
266F5CBB12FC846200DFCE33 /* Config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Config.h; path = include/lldb/Host/Config.h; sourceTree = "<group>"; };
2671A0CD134825F6003A87BB /* ConnectionMachPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConnectionMachPort.h; path = include/lldb/Core/ConnectionMachPort.h; sourceTree = "<group>"; };
2671A0CF13482601003A87BB /* ConnectionMachPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ConnectionMachPort.cpp; path = source/Core/ConnectionMachPort.cpp; sourceTree = "<group>"; };
- 2672D8461189055500FF4019 /* CommandObjectFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectFrame.cpp; path = source/Commands/CommandObjectFrame.cpp; sourceTree = "<group>"; };
+ 2672D8461189055500FF4019 /* CommandObjectFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = CommandObjectFrame.cpp; path = source/Commands/CommandObjectFrame.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
2672D8471189055500FF4019 /* CommandObjectFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectFrame.h; path = source/Commands/CommandObjectFrame.h; sourceTree = "<group>"; };
26744EED1338317700EF765A /* GDBRemoteCommunicationClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GDBRemoteCommunicationClient.cpp; sourceTree = "<group>"; };
26744EEE1338317700EF765A /* GDBRemoteCommunicationClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GDBRemoteCommunicationClient.h; sourceTree = "<group>"; };
@@ -724,7 +725,7 @@
26A0604811A5D03C00F75969 /* Baton.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Baton.cpp; path = source/Core/Baton.cpp; sourceTree = "<group>"; };
26A3B4AC1181454800381BC2 /* ObjectContainerBSDArchive.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectContainerBSDArchive.cpp; sourceTree = "<group>"; };
26A3B4AD1181454800381BC2 /* ObjectContainerBSDArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectContainerBSDArchive.h; sourceTree = "<group>"; };
- 26A4EEB511682AAC007A372A /* LLDBWrapPython.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLDBWrapPython.cpp; path = source/LLDBWrapPython.cpp; sourceTree = "<group>"; };
+ 26A4EEB511682AAC007A372A /* LLDBWrapPython.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = LLDBWrapPython.cpp; path = source/LLDBWrapPython.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
26A7A034135E6E4200FB369E /* NamedOptionValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NamedOptionValue.cpp; path = source/Interpreter/NamedOptionValue.cpp; sourceTree = "<group>"; };
26A7A036135E6E5300FB369E /* NamedOptionValue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = NamedOptionValue.h; path = include/lldb/Interpreter/NamedOptionValue.h; sourceTree = "<group>"; };
26B167A41123BF5500DC7B4F /* ThreadSafeValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadSafeValue.h; path = include/lldb/Core/ThreadSafeValue.h; sourceTree = "<group>"; };
@@ -830,7 +831,7 @@
26BC7D7E10F1B77400F91463 /* Timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Timer.h; path = include/lldb/Core/Timer.h; sourceTree = "<group>"; };
26BC7D8010F1B77400F91463 /* UserID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UserID.h; path = include/lldb/Core/UserID.h; sourceTree = "<group>"; };
26BC7D8110F1B77400F91463 /* Value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Value.h; path = include/lldb/Core/Value.h; sourceTree = "<group>"; };
- 26BC7D8210F1B77400F91463 /* ValueObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObject.h; path = include/lldb/Core/ValueObject.h; sourceTree = "<group>"; };
+ 26BC7D8210F1B77400F91463 /* ValueObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = ValueObject.h; path = include/lldb/Core/ValueObject.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
26BC7D8310F1B77400F91463 /* ValueObjectChild.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectChild.h; path = include/lldb/Core/ValueObjectChild.h; sourceTree = "<group>"; };
26BC7D8410F1B77400F91463 /* ValueObjectList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectList.h; path = include/lldb/Core/ValueObjectList.h; sourceTree = "<group>"; };
26BC7D8510F1B77400F91463 /* ValueObjectVariable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectVariable.h; path = include/lldb/Core/ValueObjectVariable.h; sourceTree = "<group>"; };
@@ -928,7 +929,7 @@
26BC7E9610F1B85900F91463 /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Timer.cpp; path = source/Core/Timer.cpp; sourceTree = "<group>"; };
26BC7E9810F1B85900F91463 /* UserID.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UserID.cpp; path = source/Core/UserID.cpp; sourceTree = "<group>"; };
26BC7E9910F1B85900F91463 /* Value.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Value.cpp; path = source/Core/Value.cpp; sourceTree = "<group>"; };
- 26BC7E9A10F1B85900F91463 /* ValueObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObject.cpp; path = source/Core/ValueObject.cpp; sourceTree = "<group>"; };
+ 26BC7E9A10F1B85900F91463 /* ValueObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = ValueObject.cpp; path = source/Core/ValueObject.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
26BC7E9B10F1B85900F91463 /* ValueObjectChild.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectChild.cpp; path = source/Core/ValueObjectChild.cpp; sourceTree = "<group>"; };
26BC7E9C10F1B85900F91463 /* ValueObjectList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectList.cpp; path = source/Core/ValueObjectList.cpp; sourceTree = "<group>"; };
26BC7E9D10F1B85900F91463 /* ValueObjectVariable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectVariable.cpp; path = source/Core/ValueObjectVariable.cpp; sourceTree = "<group>"; };
@@ -1019,8 +1020,8 @@
26DB3E141379E7AD0080DC73 /* ABISysV_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ABISysV_x86_64.h; sourceTree = "<group>"; };
26DC6A101337FE6900FF7998 /* lldb-platform */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "lldb-platform"; sourceTree = BUILT_PRODUCTS_DIR; };
26DC6A1C1337FECA00FF7998 /* lldb-platform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "lldb-platform.cpp"; path = "tools/lldb-platform/lldb-platform.cpp"; sourceTree = "<group>"; };
- 26DE1E6911616C2E00A093E2 /* lldb-forward-rtti.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-forward-rtti.h"; path = "include/lldb/lldb-forward-rtti.h"; sourceTree = "<group>"; };
- 26DE1E6A11616C2E00A093E2 /* lldb-forward.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-forward.h"; path = "include/lldb/lldb-forward.h"; sourceTree = "<group>"; };
+ 26DE1E6911616C2E00A093E2 /* lldb-forward-rtti.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = "lldb-forward-rtti.h"; path = "include/lldb/lldb-forward-rtti.h"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
+ 26DE1E6A11616C2E00A093E2 /* lldb-forward.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = "lldb-forward.h"; path = "include/lldb/lldb-forward.h"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
26DE204011618AB900A093E2 /* SBSymbolContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBSymbolContext.h; path = include/lldb/API/SBSymbolContext.h; sourceTree = "<group>"; };
26DE204211618ACA00A093E2 /* SBAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBAddress.h; path = include/lldb/API/SBAddress.h; sourceTree = "<group>"; };
26DE204411618ADA00A093E2 /* SBAddress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBAddress.cpp; path = source/API/SBAddress.cpp; sourceTree = "<group>"; };
@@ -1169,11 +1170,14 @@
69A01E1E1236C5D400C660B5 /* Mutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mutex.cpp; sourceTree = "<group>"; };
69A01E1F1236C5D400C660B5 /* Symbols.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Symbols.cpp; sourceTree = "<group>"; };
69A01E201236C5D400C660B5 /* TimeValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimeValue.cpp; sourceTree = "<group>"; };
- 9415F61613B2C0DC00A52B36 /* FormatManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FormatManager.h; path = include/lldb/Core/FormatManager.h; sourceTree = "<group>"; };
- 9415F61713B2C0EF00A52B36 /* FormatManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FormatManager.cpp; path = source/Core/FormatManager.cpp; sourceTree = "<group>"; };
+ 94031A9B13CF484600DCFF3C /* InputReaderEZ.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = InputReaderEZ.h; path = include/lldb/Core/InputReaderEZ.h; sourceTree = "<group>"; };
+ 94031A9D13CF486600DCFF3C /* InputReaderEZ.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InputReaderEZ.cpp; path = source/Core/InputReaderEZ.cpp; sourceTree = "<group>"; };
+ 94031A9F13CF5B3D00DCFF3C /* PriorityPointerPair.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PriorityPointerPair.h; path = include/lldb/Utility/PriorityPointerPair.h; sourceTree = "<group>"; };
+ 9415F61613B2C0DC00A52B36 /* FormatManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = FormatManager.h; path = include/lldb/Core/FormatManager.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
+ 9415F61713B2C0EF00A52B36 /* FormatManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = FormatManager.cpp; path = source/Core/FormatManager.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
94611EAF13CCA363003A22AF /* RefCounter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RefCounter.h; path = include/lldb/Utility/RefCounter.h; sourceTree = "<group>"; };
94611EB113CCA4A4003A22AF /* RefCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RefCounter.cpp; path = source/Utility/RefCounter.cpp; sourceTree = "<group>"; };
- 9463D4CC13B1798800C230D4 /* CommandObjectType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectType.cpp; path = source/Commands/CommandObjectType.cpp; sourceTree = "<group>"; };
+ 9463D4CC13B1798800C230D4 /* CommandObjectType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = CommandObjectType.cpp; path = source/Commands/CommandObjectType.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
9463D4CE13B179A500C230D4 /* CommandObjectType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CommandObjectType.h; path = source/Commands/CommandObjectType.h; sourceTree = "<group>"; };
9467E65113C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeHierarchyNavigator.cpp; path = source/Symbol/TypeHierarchyNavigator.cpp; sourceTree = "<group>"; };
9467E65413C3D98900B3B6F3 /* TypeHierarchyNavigator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TypeHierarchyNavigator.h; path = include/lldb/Symbol/TypeHierarchyNavigator.h; sourceTree = "<group>"; };
@@ -1797,6 +1801,7 @@
2676A093119C93C8008A98EF /* StringExtractorGDBRemote.cpp */,
2682F16B115EDA0D00CCFF99 /* PseudoTerminal.h */,
2682F16A115EDA0D00CCFF99 /* PseudoTerminal.cpp */,
+ 94031A9F13CF5B3D00DCFF3C /* PriorityPointerPair.h */,
);
name = Utility;
sourceTree = "<group>";
@@ -1929,6 +1934,8 @@
26F73061139D8FDB00FD51C7 /* History.cpp */,
9AA69DBB118A029E00D753A0 /* InputReader.h */,
9AA69DB5118A027A00D753A0 /* InputReader.cpp */,
+ 94031A9B13CF484600DCFF3C /* InputReaderEZ.h */,
+ 94031A9D13CF486600DCFF3C /* InputReaderEZ.cpp */,
9A9E1F0013980943005AC039 /* InputReaderStack.h */,
9A9E1EFE1398086D005AC039 /* InputReaderStack.cpp */,
26BC7D6510F1B77400F91463 /* IOStreamMacros.h */,
@@ -3271,6 +3278,7 @@
26ED3D6D13C563810017D45E /* OptionGroupVariable.cpp in Sources */,
26F4214413C6515B00E04E5E /* DynamicLoaderMacOSXKernel.cpp in Sources */,
94611EB213CCA4A4003A22AF /* RefCounter.cpp in Sources */,
+ 94031A9E13CF486700DCFF3C /* InputReaderEZ.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/scripts/lldb.swig b/scripts/lldb.swig
index 9d9cc25..158004c 100644
--- a/scripts/lldb.swig
+++ b/scripts/lldb.swig
@@ -359,4 +359,128 @@
return stop_at_breakpoint;
}
+SWIGEXPORT std::string
+LLDBSwigPythonCallTypeScript
+(
+ const char *python_function_name,
+ const char *session_dictionary_name,
+ const lldb::ValueObjectSP& valobj_sp
+)
+{
+ lldb::SBValue sb_value (valobj_sp);
+
+ std::string retval = "";
+
+ PyObject *ValObj_PyObj = SWIG_NewPointerObj((void *) &valobj_sp, SWIGTYPE_p_lldb__SBValue, 0);
+
+ if (ValObj_PyObj == NULL)
+ return retval;
+
+ if (!python_function_name || !session_dictionary_name)
+ return retval;
+
+ PyObject *pmodule, *main_dict, *session_dict, *pfunc;
+ PyObject *pargs, *pvalue;
+
+ pmodule = PyImport_AddModule ("__main__");
+ if (pmodule != NULL)
+ {
+ main_dict = PyModule_GetDict (pmodule);
+ if (main_dict != NULL)
+ {
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+
+ // Find the current session's dictionary in the main module's dictionary.
+
+ if (PyDict_Check (main_dict))
+
+ {
+ session_dict = NULL;
+ while (PyDict_Next (main_dict, &pos, &key, &value))
+ {
+ // We have stolen references to the key and value objects in the dictionary; we need to increment
+ // them now so that Python's garbage collector doesn't collect them out from under us.
+ Py_INCREF (key);
+ Py_INCREF (value);
+ if (strcmp (PyString_AsString (key), session_dictionary_name) == 0)
+ {
+ session_dict = value;
+ break;
+ }
+ }
+ }
+
+ if (!session_dict || !PyDict_Check (session_dict))
+ return retval;
+
+ // Find the function we need to call in the current session's dictionary.
+
+ pos = 0;
+ pfunc = NULL;
+ while (PyDict_Next (session_dict, &pos, &key, &value))
+ {
+ if (PyString_Check (key))
+ {
+ // We have stolen references to the key and value objects in the dictionary; we need to increment
+ // them now so that Python's garbage collector doesn't collect them out from under us.
+ Py_INCREF (key);
+ Py_INCREF (value);
+ if (strcmp (PyString_AsString (key), python_function_name) == 0)
+ {
+ pfunc = value;
+ break;
+ }
+ }
+ }
+
+ // Set up the arguments and call the function.
+
+ if (pfunc && PyCallable_Check (pfunc))
+ {
+ pargs = PyTuple_New (2);
+ if (pargs == NULL)
+ {
+ if (PyErr_Occurred())
+ PyErr_Clear();
+ return retval;
+ }
+
+ PyTuple_SetItem (pargs, 0, ValObj_PyObj); // This "steals" a reference to ValObj_PyObj
+ PyTuple_SetItem (pargs, 1, session_dict); // This "steals" a reference to session_dict
+ pvalue = PyObject_CallObject (pfunc, pargs);
+ Py_DECREF (pargs);
+
+ if (pvalue != NULL)
+ {
+ if (pvalue != Py_None)
+ retval = std::string(PyString_AsString(pvalue));
+ else
+ retval = "None";
+ Py_DECREF (pvalue);
+ }
+ else if (PyErr_Occurred ())
+ {
+ PyErr_Clear();
+ }
+ Py_INCREF (session_dict);
+ }
+ else if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+ }
+ else if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+ }
+ else if (PyErr_Occurred ())
+ {
+ PyErr_Clear ();
+ }
+ return retval;
+}
+
+
%}
diff --git a/source/API/SBCommandInterpreter.cpp b/source/API/SBCommandInterpreter.cpp
index 0f1914b..97b9314 100644
--- a/source/API/SBCommandInterpreter.cpp
+++ b/source/API/SBCommandInterpreter.cpp
@@ -314,6 +314,15 @@
const lldb::BreakpointLocationSP& sb_bp_loc
);
+extern "C" std::string
+LLDBSwigPythonCallTypeScript
+(
+ const char *python_function_name,
+ const char *session_dictionary_name,
+ const lldb::ValueObjectSP& valobj_sp
+);
+
+
extern "C" void init_lldb(void);
void
@@ -324,6 +333,7 @@
{
g_initialized = true;
ScriptInterpreter::InitializeInterpreter (init_lldb,
- LLDBSwigPythonBreakpointCallbackFunction);
+ LLDBSwigPythonBreakpointCallbackFunction,
+ LLDBSwigPythonCallTypeScript);
}
}
diff --git a/source/API/SBValue.cpp b/source/API/SBValue.cpp
index e51919c..aeabb17 100644
--- a/source/API/SBValue.cpp
+++ b/source/API/SBValue.cpp
@@ -472,6 +472,28 @@
return sb_value;
}
+lldb::SBValue
+SBValue::GetValueForExpressionPath(const char* expr_path)
+{
+ lldb::ValueObjectSP child_sp;
+ if (m_opaque_sp)
+ {
+ if (m_opaque_sp->GetUpdatePoint().GetTarget())
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetUpdatePoint().GetTarget()->GetAPIMutex());
+ // using default values for all the fancy options, just do it if you can
+ child_sp = m_opaque_sp->GetValueForExpressionPath(expr_path);
+ }
+ }
+
+ SBValue sb_value (child_sp);
+
+ LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBValue(%p)::GetValueForExpressionPath (expr_path=\"%s\") => SBValue(%p)", m_opaque_sp.get(), expr_path, sb_value.get());
+
+ return sb_value;
+}
uint32_t
SBValue::GetNumChildren ()
diff --git a/source/Commands/CommandObjectType.cpp b/source/Commands/CommandObjectType.cpp
index c0ffddb..b1e7c12 100644
--- a/source/Commands/CommandObjectType.cpp
+++ b/source/Commands/CommandObjectType.cpp
@@ -15,8 +15,10 @@
#include "lldb/Core/ConstString.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/FormatManager.h"
+#include "lldb/Core/InputReaderEZ.h"
#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/State.h"
+#include "lldb/Core/StringList.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -416,6 +418,162 @@
// CommandObjectTypeSummaryAdd
//-------------------------------------------------------------------------
+class ScriptAddOptions
+{
+
+public:
+
+ bool m_skip_pointers;
+ bool m_skip_references;
+ bool m_cascade;
+ bool m_callback_is_synchronous;
+ StringList m_target_types;
+ StringList m_user_source;
+
+ ScriptAddOptions(bool p,
+ bool r,
+ bool c) :
+ m_skip_pointers(p),
+ m_skip_references(r),
+ m_cascade(c),
+ m_target_types(),
+ m_user_source()
+ {
+ }
+
+ typedef lldb::SharedPtr<ScriptAddOptions>::Type SharedPointer;
+
+};
+
+static const char *g_reader_instructions = "Enter your Python command(s). Type 'DONE' to end.";
+
+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_reader_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 error #1: no script attached.\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 ("Internal error #2: no script attached.\n");
+ out_stream->Flush();
+ return;
+ }
+ StringList funct_name_sl;
+ if (!interpreter->GenerateTypeScriptFunction (options->m_user_source,
+ funct_name_sl))
+ {
+ out_stream->Printf ("Internal error #3: no script attached.\n");
+ out_stream->Flush();
+ return;
+ }
+ if (funct_name_sl.GetSize() == 0)
+ {
+ out_stream->Printf ("Internal error #4: no script attached.\n");
+ out_stream->Flush();
+ return;
+ }
+ const char *funct_name = funct_name_sl.GetStringAtIndex(0);
+ if (!funct_name || !funct_name[0])
+ {
+ out_stream->Printf ("Internal error #5: no script attached.\n");
+ out_stream->Flush();
+ return;
+ }
+ // now I have a valid function name, let's add this as script for every type in the list
+
+ SummaryFormatSP script_format;
+ script_format.reset(new ScriptSummaryFormat(options->m_cascade,
+ options->m_skip_pointers,
+ options->m_skip_references,
+ true,
+ true,
+ false,
+ std::string(funct_name),
+ options->m_user_source.CopyList(" ")));
+
+ for (int i = 0; i < options->m_target_types.GetSize(); i++)
+ {
+ const char *type_name = options->m_target_types.GetStringAtIndex(i);
+ Debugger::SummaryFormats::Add(ConstString(type_name), script_format);
+ }
+ }
+};
+
class CommandObjectTypeSummaryAdd : public CommandObject
{
@@ -471,6 +629,17 @@
case 'n':
m_name = new ConstString(option_arg);
break;
+ case 's':
+ 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;
default:
error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
break;
@@ -490,6 +659,9 @@
m_skip_pointers = false;
m_regex = false;
m_name = NULL;
+ m_python_script = "";
+ m_python_function = "";
+ m_is_add_script = false;
}
const OptionDefinition*
@@ -513,6 +685,9 @@
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;
};
CommandOptions m_options;
@@ -601,9 +776,170 @@
{
}
+ void
+ CollectPythonScript
+ (
+ ScriptAddOptions *options,
+ CommandReturnObject &result
+ )
+ {
+ InputReaderSP reader_sp (new TypeScriptAddInputReader(m_interpreter.GetDebugger()));
+ if (reader_sp && options)
+ {
+
+ Error err (reader_sp->Initialize (options));
+ 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
Execute (Args& command, CommandReturnObject &result)
{
+ if (m_options.m_is_add_script)
+ return Execute_ScriptSummary(command, result);
+ else
+ return Execute_StringSummary(command, result);
+ }
+
+ bool
+ Execute_ScriptSummary (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_python_function.empty()) // we have a Python function ready to use
+ {
+ ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
+ if (!interpreter)
+ {
+ result.AppendError ("Internal error #1N: no script attached.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ const char *funct_name = m_options.m_python_function.c_str();
+ if (!funct_name || !funct_name[0])
+ {
+ result.AppendError ("Internal error #2N: no script attached.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ // now I have a valid function name, let's add this as script for every type in the list
+
+ SummaryFormatSP script_format;
+ script_format.reset(new ScriptSummaryFormat(m_options.m_cascade,
+ m_options.m_skip_pointers,
+ m_options.m_skip_references,
+ true,
+ true,
+ false,
+ std::string(funct_name),
+ " " + m_options.m_python_function + "(valobj,dict)"));
+
+ for (int i = 0; i < command.GetArgumentCount(); i++)
+ {
+ const char *type_name = command.GetArgumentAtIndex(i);
+ Debugger::SummaryFormats::Add(ConstString(type_name), script_format);
+ }
+ }
+ else if (m_options.m_python_script.empty()) // use an InputReader to grab Python code from the user
+ {
+ ScriptAddOptions *options = new ScriptAddOptions(m_options.m_skip_pointers,
+ m_options.m_skip_references,
+ m_options.m_cascade);
+
+ for(int 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();
+ }
+ else // we have a quick 1-line script, just use it
+ {
+ ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
+ if (!interpreter)
+ {
+ result.AppendError ("Internal error #1Q: no script attached.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ StringList funct_sl;
+ funct_sl << m_options.m_python_script.c_str();
+ StringList funct_name_sl;
+ if (!interpreter->GenerateTypeScriptFunction (funct_sl,
+ funct_name_sl))
+ {
+ result.AppendError ("Internal error #2Q: no script attached.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ if (funct_name_sl.GetSize() == 0)
+ {
+ result.AppendError ("Internal error #3Q: no script attached.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ const char *funct_name = funct_name_sl.GetStringAtIndex(0);
+ if (!funct_name || !funct_name[0])
+ {
+ result.AppendError ("Internal error #4Q: no script attached.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ // now I have a valid function name, let's add this as script for every type in the list
+
+ ScriptFormatSP script_format;
+ script_format.reset(new ScriptSummaryFormat(m_options.m_cascade,
+ m_options.m_skip_pointers,
+ m_options.m_skip_references,
+ true,
+ true,
+ false,
+ std::string(funct_name),
+ " " + m_options.m_python_script));
+
+ for (int i = 0; i < command.GetArgumentCount(); i++)
+ {
+ const char *type_name = command.GetArgumentAtIndex(i);
+ Debugger::SummaryFormats::Add(ConstString(type_name), script_format);
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+ bool
+ Execute_StringSummary (Args& command, CommandReturnObject &result)
+ {
const size_t argc = command.GetArgumentCount();
if (argc < 1 && !m_options.m_name)
@@ -624,11 +960,13 @@
Error error;
- SummaryFormat::SharedPointer entry(new SummaryFormat(format_cstr,m_options.m_cascade,
- m_options.m_no_children,m_options.m_no_value,
- m_options.m_one_liner,
- m_options.m_skip_pointers,
- m_options.m_skip_references));
+ SummaryFormat::SharedPointer entry(new StringSummaryFormat(m_options.m_cascade,
+ m_options.m_skip_pointers,
+ m_options.m_skip_references,
+ m_options.m_no_children,
+ m_options.m_no_value,
+ m_options.m_one_liner,
+ format_cstr));
if (error.Fail())
{
@@ -698,6 +1036,9 @@
{ LLDB_OPT_SET_2 , true, "format-string", 'f', required_argument, NULL, 0, eArgTypeSummaryString, "Format string used to display text and object contents."},
{ LLDB_OPT_SET_2, false, "expand", 'e', no_argument, NULL, 0, eArgTypeBoolean, "Expand aggregate data types to show children on separate lines."},
{ LLDB_OPT_SET_2, false, "name", 'n', required_argument, NULL, 0, eArgTypeName, "A name for this summary string."},
+ { LLDB_OPT_SET_3, false, "python-script", 's', required_argument, NULL, 0, eArgTypeName, "Give a one-liner Python script as part of the command."},
+ { LLDB_OPT_SET_3, false, "python-function", 'F', required_argument, NULL, 0, eArgTypeName, "Give the name of a Python function to use for this type."},
+ { LLDB_OPT_SET_3, false, "input-python", 'P', no_argument, NULL, 0, eArgTypeName, "Input Python code to use for this type manually."},
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
};
@@ -808,8 +1149,8 @@
// CommandObjectTypeSummaryList
//-------------------------------------------------------------------------
-bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, const char* type, const SummaryFormat::SharedPointer& entry);
-bool CommandObjectTypeRXSummaryList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SummaryFormat::SharedPointer& entry);
+bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, const char* type, const StringSummaryFormat::SharedPointer& entry);
+bool CommandObjectTypeRXSummaryList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const StringSummaryFormat::SharedPointer& entry);
class CommandObjectTypeSummaryList;
@@ -912,16 +1253,7 @@
CommandReturnObject *result)
{
if (regex == NULL || regex->Execute(type))
- {
- result->GetOutputStream().Printf ("%s: `%s`%s%s%s%s%s%s\n", type,
- entry->m_format.c_str(),
- entry->m_cascades ? "" : " (not cascading)",
- entry->m_dont_show_children ? "" : " (show children)",
- entry->m_dont_show_value ? " (hide value)" : "",
- entry->m_show_members_oneliner ? " (one-line printout)" : "",
- entry->m_skip_pointers ? " (skip pointers)" : "",
- entry->m_skip_references ? " (skip references)" : "");
- }
+ result->GetOutputStream().Printf ("%s: %s\n", type, entry->GetDescription().c_str());
return true;
}
@@ -951,8 +1283,6 @@
}
-
-
class CommandObjectTypeFormat : public CommandObjectMultiword
{
public:
@@ -983,10 +1313,10 @@
"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)));
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeSummaryAdd (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeSummaryClear (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeSummaryDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeSummaryList (interpreter)));
}
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp
index 2c36dbb..029a1d8 100644
--- a/source/Core/Debugger.cpp
+++ b/source/Core/Debugger.cpp
@@ -733,6 +733,8 @@
// if this is a V, print the value using the default format
if (*format_name == 'V')
*val_obj_display = ValueObject::eDisplayValue;
+ if (*format_name == 'L')
+ *val_obj_display = ValueObject::eDisplayLocation;
}
// a good custom format tells us to print the value using it
else
diff --git a/source/Core/Error.cpp b/source/Core/Error.cpp
index 6e21fe7..61faca4 100644
--- a/source/Core/Error.cpp
+++ b/source/Core/Error.cpp
@@ -51,6 +51,14 @@
{
}
+Error::Error (const char* err_str):
+ m_code (0),
+ m_type (eErrorTypeInvalid),
+ m_string ()
+{
+ SetErrorString(err_str);
+}
+
//----------------------------------------------------------------------
// Assignment operator
//----------------------------------------------------------------------
diff --git a/source/Core/FormatManager.cpp b/source/Core/FormatManager.cpp
index 040b9cd..7be3791 100644
--- a/source/Core/FormatManager.cpp
+++ b/source/Core/FormatManager.cpp
@@ -14,6 +14,8 @@
// Other libraries and framework includes
// Project includes
+#include "lldb/Core/Debugger.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -217,3 +219,54 @@
return lldb::eFormatInvalid;
}
}
+
+std::string
+StringSummaryFormat::FormatObject(lldb::ValueObjectSP object)
+{
+ if (!object.get())
+ return "NULL";
+
+ StreamString s;
+ ExecutionContext exe_ctx;
+ object->GetExecutionContextScope()->CalculateExecutionContext(exe_ctx);
+ SymbolContext sc;
+ if (exe_ctx.frame)
+ sc = exe_ctx.frame->GetSymbolContext(lldb::eSymbolContextEverything);
+
+ if (m_show_members_oneliner)
+ {
+ const uint32_t num_children = object->GetNumChildren();
+ if (num_children)
+ {
+ s.PutChar('(');
+
+ for (uint32_t idx=0; idx<num_children; ++idx)
+ {
+ lldb::ValueObjectSP child_sp(object->GetChildAtIndex(idx, true));
+ if (child_sp.get())
+ {
+ if (idx)
+ s.PutCString(", ");
+ s.PutCString(child_sp.get()->GetName().AsCString());
+ s.PutChar('=');
+ s.PutCString(child_sp.get()->GetPrintableRepresentation());
+ }
+ }
+
+ s.PutChar(')');
+
+ return s.GetString();
+ }
+ else
+ return "";
+
+ }
+ else
+ {
+ if (Debugger::FormatPrompt(m_format.c_str(), &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s, NULL, object.get()))
+ return s.GetString();
+ else
+ return "";
+ }
+}
+
diff --git a/source/Core/InputReader.cpp b/source/Core/InputReader.cpp
index c6e90eb..84cd0a1 100644
--- a/source/Core/InputReader.cpp
+++ b/source/Core/InputReader.cpp
@@ -370,3 +370,14 @@
return unknown_state_string;
}
+bool
+InputReader::HandlerData::GetBatchMode()
+{
+ return reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+}
+
+lldb::StreamSP
+InputReader::HandlerData::GetOutStream()
+{
+ return reader.GetDebugger().GetAsyncOutputStream();
+}
\ No newline at end of file
diff --git a/source/Core/InputReaderEZ.cpp b/source/Core/InputReaderEZ.cpp
new file mode 100644
index 0000000..839d744
--- /dev/null
+++ b/source/Core/InputReaderEZ.cpp
@@ -0,0 +1,80 @@
+//===-- InputReaderEZ.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <string>
+
+#include "lldb/Core/InputReaderEZ.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+size_t
+InputReaderEZ::Callback_Impl(void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len)
+
+{
+ HandlerData hand_data(reader,
+ bytes,
+ bytes_len,
+ baton);
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ reader.ActivateHandler(hand_data);
+ break;
+ case eInputReaderDeactivate:
+ reader.DeactivateHandler(hand_data);
+ break;
+ case eInputReaderReactivate:
+ reader.ReactivateHandler(hand_data);
+ break;
+ case eInputReaderAsynchronousOutputWritten:
+ reader.AsynchronousOutputWrittenHandler(hand_data);
+ break;
+ case eInputReaderGotToken:
+ reader.GotTokenHandler(hand_data);
+ break;
+ case eInputReaderInterrupt:
+ reader.InterruptHandler(hand_data);
+ break;
+ case eInputReaderEndOfFile:
+ reader.EOFHandler(hand_data);
+ break;
+ case eInputReaderDone:
+ reader.DoneHandler(hand_data);
+ break;
+ }
+ return bytes_len;
+}
+
+Error
+InputReaderEZ::Initialize(void* baton,
+ lldb::InputReaderGranularity token_size,
+ const char* end_token,
+ const char *prompt,
+ bool echo)
+{
+ return InputReader::Initialize(Callback_Impl,
+ baton,
+ token_size,
+ end_token,
+ prompt,
+ echo);
+}
+
+InputReaderEZ::~InputReaderEZ ()
+{
+}
\ No newline at end of file
diff --git a/source/Core/StringList.cpp b/source/Core/StringList.cpp
index d339262..fbe0cfe 100644
--- a/source/Core/StringList.cpp
+++ b/source/Core/StringList.cpp
@@ -8,6 +8,8 @@
//===----------------------------------------------------------------------===//
#include "lldb/Core/StringList.h"
+
+#include "lldb/Core/StreamString.h"
#include "lldb/Host/FileSpec.h"
#include <string>
@@ -205,3 +207,33 @@
idx++;
}
}
+
+std::string
+StringList::CopyList(const char* item_preamble,
+ const char* items_sep)
+{
+ StreamString strm;
+ for (int i = 0; i < GetSize(); i++)
+ {
+ if (i && items_sep && items_sep[0])
+ strm << items_sep;
+ if (item_preamble)
+ strm << item_preamble;
+ strm << GetStringAtIndex(i);
+ }
+ return std::string(strm.GetData());
+}
+
+StringList&
+StringList::operator << (const char* str)
+{
+ AppendString(str);
+ return *this;
+}
+
+StringList&
+StringList::operator << (StringList strings)
+{
+ AppendList(strings);
+ return *this;
+}
\ No newline at end of file
diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp
index d8e0e0f..ca0b0ac 100644
--- a/source/Core/ValueObject.cpp
+++ b/source/Core/ValueObject.cpp
@@ -29,6 +29,8 @@
#include "lldb/Host/Endian.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+
#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/Type.h"
@@ -79,8 +81,8 @@
m_is_array_item_for_pointer(false),
m_is_bitfield_for_scalar(false),
m_last_format_mgr_revision(0),
- m_last_summary_format(),
m_last_value_format(),
+ m_last_summary_format(),
m_forced_summary_format(),
m_dump_printable_counter(0)
{
@@ -118,8 +120,8 @@
m_is_array_item_for_pointer(false),
m_is_bitfield_for_scalar(false),
m_last_format_mgr_revision(0),
- m_last_summary_format(),
m_last_value_format(),
+ m_last_summary_format(),
m_forced_summary_format(),
m_dump_printable_counter(0)
{
@@ -164,10 +166,9 @@
m_old_value_str.swap (m_value_str);
m_value_str.clear();
}
- m_location_str.clear();
- m_summary_str.clear();
- m_object_desc_str.clear();
+ ClearUserVisibleData();
+
const bool value_was_valid = GetValueIsValid();
SetValueDidChange (false);
@@ -204,15 +205,15 @@
if (m_last_format_mgr_revision != Debugger::ValueFormats::GetCurrentRevision())
{
if (m_last_summary_format.get())
- m_last_summary_format.reset((SummaryFormat*)NULL);
+ m_last_summary_format.reset((StringSummaryFormat*)NULL);
if (m_last_value_format.get())
m_last_value_format.reset((ValueFormat*)NULL);
Debugger::ValueFormats::Get(*this, m_last_value_format);
if (!Debugger::SummaryFormats::Get(*this, m_last_summary_format))
Debugger::RegexSummaryFormats::Get(*this, m_last_summary_format);
m_last_format_mgr_revision = Debugger::ValueFormats::GetCurrentRevision();
- m_value_str.clear();
- m_summary_str.clear();
+
+ ClearUserVisibleData();
}
}
@@ -507,221 +508,177 @@
{
if (m_summary_str.empty())
{
- SummaryFormat* summary_format = GetSummaryFormat().get();
+ SummaryFormat *summary_format = GetSummaryFormat().get();
if (summary_format)
{
- StreamString s;
- ExecutionContext exe_ctx;
- this->GetExecutionContextScope()->CalculateExecutionContext(exe_ctx);
- SymbolContext sc;
- if (exe_ctx.frame)
- sc = exe_ctx.frame->GetSymbolContext(eSymbolContextEverything);
-
- if (summary_format->m_show_members_oneliner)
- {
- const uint32_t num_children = GetNumChildren();
- if (num_children)
- {
-
- s.PutChar('(');
-
- for (uint32_t idx=0; idx<num_children; ++idx)
- {
- ValueObjectSP child_sp(GetChildAtIndex(idx, true));
- if (child_sp.get())
- {
- if (idx)
- s.PutCString(", ");
- s.PutCString(child_sp.get()->GetName().AsCString());
- s.PutChar('=');
- s.PutCString(child_sp.get()->GetPrintableRepresentation());
- }
- }
-
- s.PutChar(')');
-
- m_summary_str.swap(s.GetString());
- return m_summary_str.c_str();
- }
- else
- return "()";
-
- }
- else
- {
- if (Debugger::FormatPrompt(summary_format->m_format.c_str(), &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s, NULL, this))
- {
- m_summary_str.swap(s.GetString());
- return m_summary_str.c_str();
- }
- else
- return NULL;
- }
+ m_summary_str = summary_format->FormatObject(GetSP());
}
-
- clang_type_t clang_type = GetClangType();
-
- // See if this is a pointer to a C string?
- if (clang_type)
+ else
{
- StreamString sstr;
- clang_type_t elem_or_pointee_clang_type;
- const Flags type_flags (ClangASTContext::GetTypeInfo (clang_type,
- GetClangAST(),
- &elem_or_pointee_clang_type));
+ clang_type_t clang_type = GetClangType();
- ExecutionContextScope *exe_scope = GetExecutionContextScope();
- if (exe_scope)
+ // See if this is a pointer to a C string?
+ if (clang_type)
{
- if (type_flags.AnySet (ClangASTContext::eTypeIsArray | ClangASTContext::eTypeIsPointer) &&
- ClangASTContext::IsCharType (elem_or_pointee_clang_type))
- {
- Target *target = exe_scope->CalculateTarget();
- if (target != NULL)
- {
- lldb::addr_t cstr_address = LLDB_INVALID_ADDRESS;
- AddressType cstr_address_type = eAddressTypeInvalid;
+ StreamString sstr;
+ clang_type_t elem_or_pointee_clang_type;
+ const Flags type_flags (ClangASTContext::GetTypeInfo (clang_type,
+ GetClangAST(),
+ &elem_or_pointee_clang_type));
- size_t cstr_len = 0;
- bool capped_data = false;
- if (type_flags.Test (ClangASTContext::eTypeIsArray))
+ ExecutionContextScope *exe_scope = GetExecutionContextScope();
+ if (exe_scope)
+ {
+ if (type_flags.AnySet (ClangASTContext::eTypeIsArray | ClangASTContext::eTypeIsPointer) &&
+ ClangASTContext::IsCharType (elem_or_pointee_clang_type))
+ {
+ Target *target = exe_scope->CalculateTarget();
+ if (target != NULL)
{
- // We have an array
- cstr_len = ClangASTContext::GetArraySize (clang_type);
- if (cstr_len > 512) // TODO: make cap a setting
+ lldb::addr_t cstr_address = LLDB_INVALID_ADDRESS;
+ AddressType cstr_address_type = eAddressTypeInvalid;
+
+ size_t cstr_len = 0;
+ bool capped_data = false;
+ if (type_flags.Test (ClangASTContext::eTypeIsArray))
{
+ // We have an array
cstr_len = ClangASTContext::GetArraySize (clang_type);
if (cstr_len > 512) // TODO: make cap a setting
{
- capped_data = true;
- cstr_len = 512;
+ cstr_len = ClangASTContext::GetArraySize (clang_type);
+ if (cstr_len > 512) // TODO: make cap a setting
+ {
+ capped_data = true;
+ cstr_len = 512;
+ }
}
- }
- cstr_address = GetAddressOf (cstr_address_type, true);
- }
- else
- {
- // We have a pointer
- cstr_address = GetPointerValue (cstr_address_type, true);
- }
- if (cstr_address != LLDB_INVALID_ADDRESS)
- {
- Address cstr_so_addr (NULL, cstr_address);
- DataExtractor data;
- size_t bytes_read = 0;
- std::vector<char> data_buffer;
- Error error;
- bool prefer_file_cache = false;
- if (cstr_len > 0)
- {
- data_buffer.resize(cstr_len);
- data.SetData (&data_buffer.front(), data_buffer.size(), lldb::endian::InlHostByteOrder());
- bytes_read = target->ReadMemory (cstr_so_addr,
- prefer_file_cache,
- &data_buffer.front(),
- cstr_len,
- error);
- if (bytes_read > 0)
- {
- sstr << '"';
- data.Dump (&sstr,
- 0, // Start offset in "data"
- eFormatCharArray, // Print as characters
- 1, // Size of item (1 byte for a char!)
- bytes_read, // How many bytes to print?
- UINT32_MAX, // num per line
- LLDB_INVALID_ADDRESS,// base address
- 0, // bitfield bit size
- 0); // bitfield bit offset
- if (capped_data)
- sstr << "...";
- sstr << '"';
- }
+ cstr_address = GetAddressOf (cstr_address_type, true);
}
else
{
- const size_t k_max_buf_size = 256;
- data_buffer.resize (k_max_buf_size + 1);
- // NULL terminate in case we don't get the entire C string
- data_buffer.back() = '\0';
-
- sstr << '"';
-
- data.SetData (&data_buffer.front(), data_buffer.size(), endian::InlHostByteOrder());
- while ((bytes_read = target->ReadMemory (cstr_so_addr,
- prefer_file_cache,
- &data_buffer.front(),
- k_max_buf_size,
- error)) > 0)
- {
- size_t len = strlen(&data_buffer.front());
- if (len == 0)
- break;
- if (len > bytes_read)
- len = bytes_read;
-
- data.Dump (&sstr,
- 0, // Start offset in "data"
- eFormatCharArray, // Print as characters
- 1, // Size of item (1 byte for a char!)
- len, // How many bytes to print?
- UINT32_MAX, // num per line
- LLDB_INVALID_ADDRESS,// base address
- 0, // bitfield bit size
- 0); // bitfield bit offset
-
- if (len < k_max_buf_size)
- break;
- cstr_so_addr.Slide (k_max_buf_size);
- }
- sstr << '"';
+ // We have a pointer
+ cstr_address = GetPointerValue (cstr_address_type, true);
}
- }
- }
-
- if (sstr.GetSize() > 0)
- m_summary_str.assign (sstr.GetData(), sstr.GetSize());
- }
- else if (ClangASTContext::IsFunctionPointerType (clang_type))
- {
- AddressType func_ptr_address_type = eAddressTypeInvalid;
- lldb::addr_t func_ptr_address = GetPointerValue (func_ptr_address_type, true);
-
- if (func_ptr_address != 0 && func_ptr_address != LLDB_INVALID_ADDRESS)
- {
- switch (func_ptr_address_type)
- {
- case eAddressTypeInvalid:
- case eAddressTypeFile:
- break;
-
- case eAddressTypeLoad:
+ if (cstr_address != LLDB_INVALID_ADDRESS)
{
- Address so_addr;
- Target *target = exe_scope->CalculateTarget();
- if (target && target->GetSectionLoadList().IsEmpty() == false)
+ Address cstr_so_addr (NULL, cstr_address);
+ DataExtractor data;
+ size_t bytes_read = 0;
+ std::vector<char> data_buffer;
+ Error error;
+ bool prefer_file_cache = false;
+ if (cstr_len > 0)
{
- if (target->GetSectionLoadList().ResolveLoadAddress(func_ptr_address, so_addr))
+ data_buffer.resize(cstr_len);
+ data.SetData (&data_buffer.front(), data_buffer.size(), lldb::endian::InlHostByteOrder());
+ bytes_read = target->ReadMemory (cstr_so_addr,
+ prefer_file_cache,
+ &data_buffer.front(),
+ cstr_len,
+ error);
+ if (bytes_read > 0)
{
- so_addr.Dump (&sstr,
- exe_scope,
- Address::DumpStyleResolvedDescription,
- Address::DumpStyleSectionNameOffset);
+ sstr << '"';
+ data.Dump (&sstr,
+ 0, // Start offset in "data"
+ eFormatCharArray, // Print as characters
+ 1, // Size of item (1 byte for a char!)
+ bytes_read, // How many bytes to print?
+ UINT32_MAX, // num per line
+ LLDB_INVALID_ADDRESS,// base address
+ 0, // bitfield bit size
+ 0); // bitfield bit offset
+ if (capped_data)
+ sstr << "...";
+ sstr << '"';
}
}
- }
- break;
+ else
+ {
+ const size_t k_max_buf_size = 256;
+ data_buffer.resize (k_max_buf_size + 1);
+ // NULL terminate in case we don't get the entire C string
+ data_buffer.back() = '\0';
- case eAddressTypeHost:
- break;
+ sstr << '"';
+
+ data.SetData (&data_buffer.front(), data_buffer.size(), endian::InlHostByteOrder());
+ while ((bytes_read = target->ReadMemory (cstr_so_addr,
+ prefer_file_cache,
+ &data_buffer.front(),
+ k_max_buf_size,
+ error)) > 0)
+ {
+ size_t len = strlen(&data_buffer.front());
+ if (len == 0)
+ break;
+ if (len > bytes_read)
+ len = bytes_read;
+
+ data.Dump (&sstr,
+ 0, // Start offset in "data"
+ eFormatCharArray, // Print as characters
+ 1, // Size of item (1 byte for a char!)
+ len, // How many bytes to print?
+ UINT32_MAX, // num per line
+ LLDB_INVALID_ADDRESS,// base address
+ 0, // bitfield bit size
+ 0); // bitfield bit offset
+
+ if (len < k_max_buf_size)
+ break;
+ cstr_so_addr.Slide (k_max_buf_size);
+ }
+ sstr << '"';
+ }
+ }
}
+
+ if (sstr.GetSize() > 0)
+ m_summary_str.assign (sstr.GetData(), sstr.GetSize());
}
- if (sstr.GetSize() > 0)
+ else if (ClangASTContext::IsFunctionPointerType (clang_type))
{
- m_summary_str.assign (1, '(');
- m_summary_str.append (sstr.GetData(), sstr.GetSize());
- m_summary_str.append (1, ')');
+ AddressType func_ptr_address_type = eAddressTypeInvalid;
+ lldb::addr_t func_ptr_address = GetPointerValue (func_ptr_address_type, true);
+
+ if (func_ptr_address != 0 && func_ptr_address != LLDB_INVALID_ADDRESS)
+ {
+ switch (func_ptr_address_type)
+ {
+ case eAddressTypeInvalid:
+ case eAddressTypeFile:
+ break;
+
+ case eAddressTypeLoad:
+ {
+ Address so_addr;
+ Target *target = exe_scope->CalculateTarget();
+ if (target && target->GetSectionLoadList().IsEmpty() == false)
+ {
+ if (target->GetSectionLoadList().ResolveLoadAddress(func_ptr_address, so_addr))
+ {
+ so_addr.Dump (&sstr,
+ exe_scope,
+ Address::DumpStyleResolvedDescription,
+ Address::DumpStyleSectionNameOffset);
+ }
+ }
+ }
+ break;
+
+ case eAddressTypeHost:
+ break;
+ }
+ }
+ if (sstr.GetSize() > 0)
+ {
+ m_summary_str.assign (1, '(');
+ m_summary_str.append (sstr.GetData(), sstr.GetSize());
+ m_summary_str.append (1, ')');
+ }
}
}
}
@@ -960,34 +917,35 @@
clang_type_t clang_type = GetClangType ();
if (clang_type)
{
- StreamString sstr;
- Format format = GetFormat();
- if (format == eFormatDefault)
+ if (m_last_value_format)
{
- if (m_last_value_format)
- format = m_last_value_format->m_format;
- else
- // force the system into using unsigned integers for bitfields
- format = (m_is_bitfield_for_scalar ? eFormatUnsigned :
- ClangASTType::GetFormat(clang_type));
+ m_value_str = m_last_value_format->FormatObject(GetSP());
}
-
- if (ClangASTType::DumpTypeValue (GetClangAST(), // The clang AST
- clang_type, // The clang type to display
- &sstr,
- format, // Format to display this type with
- m_data, // Data to extract from
- 0, // Byte offset into "m_data"
- GetByteSize(), // Byte size of item in "m_data"
- GetBitfieldBitSize(), // Bitfield bit size
- GetBitfieldBitOffset())) // Bitfield bit offset
- m_value_str.swap(sstr.GetString());
else
{
- m_error.SetErrorStringWithFormat ("unsufficient data for value (only %u of %u bytes available)",
- m_data.GetByteSize(),
- GetByteSize());
- m_value_str.clear();
+ StreamString sstr;
+ Format format = GetFormat();
+ if (format == eFormatDefault)
+ format = (m_is_bitfield_for_scalar ? eFormatUnsigned :
+ ClangASTType::GetFormat(clang_type));
+
+ if (ClangASTType::DumpTypeValue (GetClangAST(), // The clang AST
+ clang_type, // The clang type to display
+ &sstr,
+ format, // Format to display this type with
+ m_data, // Data to extract from
+ 0, // Byte offset into "m_data"
+ GetByteSize(), // Byte size of item in "m_data"
+ GetBitfieldBitSize(), // Bitfield bit size
+ GetBitfieldBitOffset())) // Bitfield bit offset
+ m_value_str.swap(sstr.GetString());
+ else
+ {
+ m_error.SetErrorStringWithFormat ("unsufficient data for value (only %u of %u bytes available)",
+ m_data.GetByteSize(),
+ GetByteSize());
+ m_value_str.clear();
+ }
}
}
}
@@ -1046,6 +1004,9 @@
case eDisplayLanguageSpecific:
return_value = GetObjectDescription();
break;
+ case eDisplayLocation:
+ return_value = GetLocationAsCString();
+ break;
}
// this code snippet might lead to endless recursion, thus we use a RefCounter here to
@@ -3221,3 +3182,12 @@
return needs_update;
}
+
+void
+ValueObject::ClearUserVisibleData()
+{
+ m_location_str.clear();
+ m_value_str.clear();
+ m_summary_str.clear();
+ m_object_desc_str.clear();
+}
\ No newline at end of file
diff --git a/source/Interpreter/ScriptInterpreter.cpp b/source/Interpreter/ScriptInterpreter.cpp
index 7011c2e..294aeec 100644
--- a/source/Interpreter/ScriptInterpreter.cpp
+++ b/source/Interpreter/ScriptInterpreter.cpp
@@ -92,10 +92,12 @@
void
ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
- SWIGBreakpointCallbackFunction python_swig_breakpoint_callback)
+ SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
+ SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback)
{
ScriptInterpreterPython::InitializeInterpreter (python_swig_init_callback,
- python_swig_breakpoint_callback);
+ python_swig_breakpoint_callback,
+ python_swig_typescript_callback);
}
void
diff --git a/source/Interpreter/ScriptInterpreterPython.cpp b/source/Interpreter/ScriptInterpreterPython.cpp
index 610c019..57a5929 100644
--- a/source/Interpreter/ScriptInterpreterPython.cpp
+++ b/source/Interpreter/ScriptInterpreterPython.cpp
@@ -34,6 +34,7 @@
static ScriptInterpreter::SWIGInitCallback g_swig_init_callback = NULL;
static ScriptInterpreter::SWIGBreakpointCallbackFunction g_swig_breakpoint_callback = NULL;
+static ScriptInterpreter::SWIGPythonTypeScriptCallbackFunction g_swig_typescript_callback = NULL;
static int
@@ -1140,6 +1141,117 @@
return ExecuteMultipleLines (function_def_string.c_str());
}
+// TODO move both GenerateTypeScriptFunction and GenerateBreakpointCommandCallbackData to actually
+// use this code to generate their functions
+bool
+ScriptInterpreterPython::GenerateFunction(std::string& signature, StringList &input, StringList &output)
+{
+ int num_lines = input.GetSize ();
+ if (num_lines == 0)
+ return false;
+ StreamString sstr;
+ StringList auto_generated_function;
+ auto_generated_function.AppendString (signature.c_str());
+ auto_generated_function.AppendString (" global_dict = globals()"); // Grab the global dictionary
+ auto_generated_function.AppendString (" new_keys = dict.keys()"); // Make a list of keys in the session dict
+ auto_generated_function.AppendString (" old_keys = global_dict.keys()"); // Save list of keys in global dict
+ auto_generated_function.AppendString (" global_dict.update (dict)"); // Add the session dictionary to the
+ // global dictionary.
+
+ // Wrap everything up inside the function, increasing the indentation.
+
+ for (int i = 0; i < num_lines; ++i)
+ {
+ sstr.Clear ();
+ sstr.Printf (" %s", input.GetStringAtIndex (i));
+ auto_generated_function.AppendString (sstr.GetData());
+ }
+ auto_generated_function.AppendString (" for key in new_keys:"); // Iterate over all the keys from session dict
+ auto_generated_function.AppendString (" dict[key] = global_dict[key]"); // Update session dict values
+ auto_generated_function.AppendString (" if key not in old_keys:"); // If key was not originally in global dict
+ auto_generated_function.AppendString (" del global_dict[key]"); // ...then remove key/value from global dict
+
+ // Verify that the results are valid Python.
+
+ if (!ExportFunctionDefinitionToInterpreter (auto_generated_function))
+ return false;
+
+ return true;
+
+}
+
+// this implementation is identical to GenerateBreakpointCommandCallbackData (apart from the name
+// given to generated functions, of course)
+bool
+ScriptInterpreterPython::GenerateTypeScriptFunction (StringList &user_input, StringList &output)
+{
+ static int num_created_functions = 0;
+ user_input.RemoveBlankLines ();
+ int num_lines = user_input.GetSize ();
+ StreamString sstr;
+
+ // Check to see if we have any data; if not, just return.
+ if (user_input.GetSize() == 0)
+ return false;
+
+ // Take what the user wrote, wrap it all up inside one big auto-generated Python function, passing in the
+ // ValueObject as parameter to the function.
+
+ sstr.Printf ("lldb_autogen_python_type_print_func_%d", num_created_functions);
+ ++num_created_functions;
+ std::string auto_generated_function_name = sstr.GetData();
+
+ sstr.Clear();
+ StringList auto_generated_function;
+
+ // Create the function name & definition string.
+
+ sstr.Printf ("def %s (valobj, dict):", auto_generated_function_name.c_str());
+ auto_generated_function.AppendString (sstr.GetData());
+
+ // Pre-pend code for setting up the session dictionary.
+
+ auto_generated_function.AppendString (" global_dict = globals()"); // Grab the global dictionary
+ auto_generated_function.AppendString (" new_keys = dict.keys()"); // Make a list of keys in the session dict
+ auto_generated_function.AppendString (" old_keys = global_dict.keys()"); // Save list of keys in global dict
+ auto_generated_function.AppendString (" global_dict.update (dict)"); // Add the session dictionary to the
+ // global dictionary.
+
+ // Wrap everything up inside the function, increasing the indentation.
+
+ for (int i = 0; i < num_lines; ++i)
+ {
+ sstr.Clear ();
+ sstr.Printf (" %s", user_input.GetStringAtIndex (i));
+ auto_generated_function.AppendString (sstr.GetData());
+ }
+
+ // Append code to clean up the global dictionary and update the session dictionary (all updates in the function
+ // got written to the values in the global dictionary, not the session dictionary).
+
+ auto_generated_function.AppendString (" for key in new_keys:"); // Iterate over all the keys from session dict
+ auto_generated_function.AppendString (" dict[key] = global_dict[key]"); // Update session dict values
+ auto_generated_function.AppendString (" if key not in old_keys:"); // If key was not originally in global dict
+ auto_generated_function.AppendString (" del global_dict[key]"); // ...then remove key/value from global dict
+
+ // Verify that the results are valid Python.
+
+ if (!ExportFunctionDefinitionToInterpreter (auto_generated_function))
+ return false;
+
+ // Store the name of the auto-generated function to be called.
+
+ output.AppendString (auto_generated_function_name.c_str());
+ return true;
+}
+
+bool
+ScriptInterpreterPython::GenerateTypeScriptFunction (const char* oneliner, StringList &output)
+{
+ StringList input(oneliner);
+ return GenerateTypeScriptFunction(input, output);
+}
+
bool
ScriptInterpreterPython::GenerateBreakpointCommandCallbackData (StringList &user_input, StringList &callback_data)
{
@@ -1206,6 +1318,63 @@
return true;
}
+std::string
+ScriptInterpreterPython::CallPythonScriptFunction (const char *python_function_name,
+ lldb::ValueObjectSP valobj)
+{
+
+ if (!python_function_name || !(*python_function_name))
+ return "<no function>";
+
+ if (!valobj.get())
+ return "<no object>";
+
+ Target *target = valobj->GetUpdatePoint().GetTarget();
+
+ if (!target)
+ return "<no target>";
+
+ Debugger &debugger = target->GetDebugger();
+ ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
+ ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter;
+
+ if (!script_interpreter)
+ return "<no python>";
+
+ std::string ret_val;
+
+ if (python_function_name
+ && *python_function_name)
+ {
+ FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
+ if (CurrentThreadHasPythonLock())
+ {
+ python_interpreter->EnterSession ();
+ ret_val = g_swig_typescript_callback (python_function_name,
+ python_interpreter->m_dictionary_name.c_str(),
+ valobj);
+ python_interpreter->LeaveSession ();
+ }
+ else
+ {
+ while (!GetPythonLock (1))
+ fprintf (tmp_fh,
+ "Python interpreter locked on another thread; waiting to acquire lock...\n");
+ python_interpreter->EnterSession ();
+ ret_val = g_swig_typescript_callback (python_function_name,
+ python_interpreter->m_dictionary_name.c_str(),
+ valobj);
+ python_interpreter->LeaveSession ();
+ ReleasePythonLock ();
+ }
+ }
+ else
+ return "<no function name>";
+
+ return ret_val;
+
+}
+
bool
ScriptInterpreterPython::BreakpointCallbackFunction
(
@@ -1399,10 +1568,12 @@
void
ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
- SWIGBreakpointCallbackFunction python_swig_breakpoint_callback)
+ SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
+ SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback)
{
g_swig_init_callback = python_swig_init_callback;
- g_swig_breakpoint_callback = python_swig_breakpoint_callback;
+ g_swig_breakpoint_callback = python_swig_breakpoint_callback;
+ g_swig_typescript_callback = python_swig_typescript_callback;
}
void
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index 0619c10..9712d6f 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -19,6 +19,7 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/TimeValue.h"
#include "lldb/Target/Process.h"
diff --git a/test/functionalities/data-formatter/data-formatter-script/Makefile b/test/functionalities/data-formatter/data-formatter-script/Makefile
new file mode 100644
index 0000000..314f1cb
--- /dev/null
+++ b/test/functionalities/data-formatter/data-formatter-script/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/test/functionalities/data-formatter/data-formatter-script/TestDataFormatterScript.py b/test/functionalities/data-formatter/data-formatter-script/TestDataFormatterScript.py
new file mode 100644
index 0000000..77a0368
--- /dev/null
+++ b/test/functionalities/data-formatter/data-formatter-script/TestDataFormatterScript.py
@@ -0,0 +1,110 @@
+"""
+Test lldb data formatter subsystem.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+
+class DataFormatterTestCase(TestBase):
+
+ mydir = os.path.join("functionalities", "data-formatter", "data-formatter-script")
+
+ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+ def test_with_dsym_and_run_command(self):
+ """Test data formatter commands."""
+ self.buildDsym()
+ self.data_formatter_commands()
+
+ def test_with_dwarf_and_run_command(self):
+ """Test data formatter commands."""
+ self.buildDwarf()
+ self.data_formatter_commands()
+
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+ # Find the line number to break at.
+ self.line = line_number('main.cpp', '// Set break point at this line.')
+
+ def data_formatter_commands(self):
+ """Test that that file and class static variables display correctly."""
+ self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+
+ self.expect("breakpoint set -f main.cpp -l %d" % self.line,
+ BREAKPOINT_CREATED,
+ startstr = "Breakpoint created: 1: file ='main.cpp', line = %d, locations = 1" %
+ self.line)
+
+ self.runCmd("run", RUN_SUCCEEDED)
+
+ # The stop reason of the thread should be breakpoint.
+ self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+ substrs = ['stopped',
+ 'stop reason = breakpoint'])
+
+ # This is the function to remove the custom formats in order to have a
+ # clean slate for the next test case.
+ def cleanup():
+ self.runCmd('type format clear', check=False)
+ self.runCmd('type summary clear', check=False)
+
+ # Execute the cleanup function during test case tear down.
+ self.addTearDownHook(cleanup)
+
+ # Set the script here to ease the formatting
+ script = 'a = valobj.GetChildMemberWithName(\'integer\'); a_val = a.GetValue(); str = \'Hello from Python, \' + a_val + \' time\'; return str + (\'!\' if a_val == \'1\' else \'s!\');'
+
+ self.runCmd("type summary add add i_am_cool -s \"%s\"" % script)
+
+ self.expect("frame variable one",
+ substrs = ['Hello from Python',
+ '1 time!'])
+
+ self.expect("frame variable two",
+ substrs = ['Hello from Python',
+ '4 times!'])
+
+ self.runCmd("n"); # skip ahead to make values change
+
+ self.expect("frame variable three",
+ substrs = ['Hello from Python, 10 times!',
+ 'Hello from Python, 4 times!'])
+
+ self.runCmd("n"); # skip ahead to make values change
+
+ self.expect("frame variable two",
+ substrs = ['Hello from Python',
+ '1 time!'])
+
+ script = 'a = valobj.GetChildMemberWithName(\'integer\'); a_val = a.GetValue(); str = \'int says \' + a_val; return str;'
+
+ # Check that changes in the script are immediately reflected
+ self.runCmd("type summary add i_am_cool -s \"%s\"" % script)
+
+ self.expect("frame variable two",
+ substrs = ['int says 1'])
+
+ # Change the summary
+ self.runCmd("type summary add -f \"int says ${var.integer}, and float says ${var.floating}\" i_am_cool")
+
+ self.expect("frame variable two",
+ substrs = ['int says 1',
+ 'and float says 2.71'])
+ # Try it for pointers
+ self.expect("frame variable twoptr",
+ substrs = ['int says 1',
+ 'and float says 2.71'])
+
+ # Force a failure for pointers
+ self.runCmd("type summary add i_am_cool -p -s \"%s\"" % script)
+
+ self.expect("frame variable twoptr", matching=False,
+ substrs = ['and float says 2.71'])
+
+if __name__ == '__main__':
+ import atexit
+ lldb.SBDebugger.Initialize()
+ atexit.register(lambda: lldb.SBDebugger.Terminate())
+ unittest2.main()
diff --git a/test/functionalities/data-formatter/data-formatter-script/main.cpp b/test/functionalities/data-formatter/data-formatter-script/main.cpp
new file mode 100644
index 0000000..3570622
--- /dev/null
+++ b/test/functionalities/data-formatter/data-formatter-script/main.cpp
@@ -0,0 +1,49 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+struct i_am_cool
+{
+ int integer;
+ float floating;
+ char character;
+ i_am_cool(int I, float F, char C) :
+ integer(I), floating(F), character(C) {}
+ i_am_cool() : integer(1), floating(2), character('3') {}
+
+};
+
+struct i_am_cooler
+{
+ i_am_cool first_cool;
+ i_am_cool second_cool;
+ float floating;
+
+ i_am_cooler(int I1, int I2, float F1, float F2, char C1, char C2) :
+ first_cool(I1,F1,C1),
+ second_cool(I2,F2,C2),
+ floating((F1 + F2)/2) {}
+};
+
+int main (int argc, const char * argv[])
+{
+ i_am_cool one(1,3.14,'E');
+ i_am_cool two(4,2.71,'G');
+
+ i_am_cool* twoptr = &two;
+
+ i_am_cooler three(10,4,1985,1/1/2011,'B','E'); // Set break point at this line.
+
+ two.integer = 1;
+
+ return 0;
+}
\ No newline at end of file
diff --git a/www/varformats.html b/www/varformats.html
index b0a1af1..3fd647d 100755
--- a/www/varformats.html
+++ b/www/varformats.html
@@ -784,6 +784,17 @@
(i_am_cool) one = x=3<br>
</code> </p>
+ <p>When defining a named summmary, binding it to one or more types becomes optional.
+ Even if you bind the named summary to a type, and later change the summary string
+ for that type, the named summary will not be changed by that. You can delete
+ named summaries by using the <code>type summary delete</code> command, as if the
+ summary name was the datatype that the summary is applied to</p>
+
+ <p>A summary attached to a variable using the </code>--summary</code> option,
+ has the same semantics that a custom format attached using the <code>-f</code>
+ option has: it stays attached till you attach a new one, or till you let
+ your program run again.</p>
+
</div>
</div>