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

llvm-svn: 135238
This commit is contained in:
Enrico Granata 2011-07-15 02:26:42 +00:00
parent a83b37a9db
commit f2bbf717f7
33 changed files with 1902 additions and 282 deletions

View File

@ -167,6 +167,10 @@ public:
// 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 @@ public:
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...

View File

@ -576,8 +576,6 @@ public:
static uint32_t
GetCount();
};
};
} // namespace lldb_private

View File

@ -69,6 +69,9 @@ public:
explicit
Error (ValueType err, lldb::ErrorType type = lldb::eErrorTypeGeneric);
explicit
Error (const char* err_str);
Error (const Error &rhs);
//------------------------------------------------------------------
/// Assignment operator.

View File

@ -50,8 +50,10 @@ namespace std
#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,7 +69,262 @@ public:
};
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;
@ -116,32 +373,35 @@ struct SummaryFormat
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 @@ private:
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 @@ private:
NamedSummariesMap m_named_summaries_map;
ScriptNavigator m_script_nav;
uint32_t m_last_revision;
public:
@ -478,6 +742,7 @@ public:
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 @@ public:
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,

View File

@ -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 @@ public:
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 @@ public:
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
{

View File

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

View File

@ -68,7 +68,17 @@ public:
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;

View File

@ -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 @@ public:
{
eDisplayValue = 1,
eDisplaySummary,
eDisplayLanguageSpecific
eDisplayLanguageSpecific,
eDisplayLocation
};
enum ExpressionPathScanEndReason
@ -731,8 +733,8 @@ protected:
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 @@ protected:
void
SetValueIsValid (bool valid);
void
ClearUserVisibleData();
public:
lldb::addr_t

View File

@ -26,6 +26,13 @@ public:
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 @@ public:
{
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 @@ public:
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 ();

View File

@ -49,6 +49,16 @@ public:
bool
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);
@ -64,6 +74,10 @@ public:
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 @@ public:
static void
InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
SWIGBreakpointCallbackFunction python_swig_breakpoint_callback);
SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback);
protected:

View File

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

View File

@ -20,8 +20,6 @@ namespace lldb_utility {
// 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

View File

@ -56,11 +56,13 @@ namespace lldb {
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;

View File

@ -114,6 +114,7 @@ class RegisterLocationList;
class RegisterValue;
class RegularExpression;
class Scalar;
class ScriptSummaryFormat;
class ScriptInterpreter;
class ScriptInterpreterPython;
class SearchFilter;
@ -131,6 +132,7 @@ class Stream;
class StreamFile;
class StreamString;
class StringList;
class StringSummaryFormat;
class SummaryFormat;
class Symbol;
class SymbolContext;

View File

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

View File

@ -359,4 +359,128 @@ LLDBSwigPythonBreakpointCallbackFunction
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;
}
%}

View File

@ -314,6 +314,15 @@ LLDBSwigPythonBreakpointCallbackFunction
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 @@ SBCommandInterpreter::InitializeSWIG ()
{
g_initialized = true;
ScriptInterpreter::InitializeInterpreter (init_lldb,
LLDBSwigPythonBreakpointCallbackFunction);
LLDBSwigPythonBreakpointCallbackFunction,
LLDBSwigPythonCallTypeScript);
}
}

View File

@ -472,6 +472,28 @@ SBValue::GetChildMemberWithName (const char *name, lldb::DynamicValueType use_dy
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 ()

View File

@ -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 @@ CommandObjectTypeFormatList_LoopCallback (
// 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 @@ private:
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 @@ private:
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 @@ private:
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,8 +776,169 @@ public:
{
}
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();
@ -624,11 +960,13 @@ public:
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 @@ CommandObjectTypeSummaryAdd::CommandOptions::g_option_table[] =
{ 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 @@ public:
// 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 @@ private:
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 @@ CommandObjectTypeRXSummaryList_LoopCallback (
}
class CommandObjectTypeFormat : public CommandObjectMultiword
{
public:
@ -983,10 +1313,10 @@ public:
"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)));
}

View File

@ -733,6 +733,8 @@ ScanFormatDescriptor(const char* var_name_begin,
// 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

View File

@ -51,6 +51,14 @@ Error::Error (const Error &rhs) :
{
}
Error::Error (const char* err_str):
m_code (0),
m_type (eErrorTypeInvalid),
m_string ()
{
SetErrorString(err_str);
}
//----------------------------------------------------------------------
// Assignment operator
//----------------------------------------------------------------------

View File

@ -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 @@ FormatManager::GetSingleItemFormat(lldb::Format vector_format)
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 "";
}
}

View File

@ -370,3 +370,14 @@ InputReader::GranularityAsCString (lldb::InputReaderGranularity granularity)
return unknown_state_string;
}
bool
InputReader::HandlerData::GetBatchMode()
{
return reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
}
lldb::StreamSP
InputReader::HandlerData::GetOutStream()
{
return reader.GetDebugger().GetAsyncOutputStream();
}

View File

@ -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 ()
{
}

View File

@ -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 @@ StringList::RemoveBlankLines ()
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;
}

View File

@ -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 @@ ValueObject::ValueObject (ValueObject &parent) :
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 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope) :
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 @@ ValueObject::UpdateValueIfNeeded (bool update_format)
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 @@ ValueObject::UpdateFormatsIfNeeded()
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 @@ ValueObject::GetSummaryAsCString ()
{
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_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_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
{
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 @@ ValueObject::GetValueAsCString ()
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 @@ ValueObject::GetPrintableRepresentation(ValueObjectRepresentationStyle val_obj_d
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 @@ ValueObject::EvaluationPoint::SetContext (ExecutionContextScope *exe_scope)
return needs_update;
}
void
ValueObject::ClearUserVisibleData()
{
m_location_str.clear();
m_value_str.clear();
m_summary_str.clear();
m_object_desc_str.clear();
}

View File

@ -92,10 +92,12 @@ ScriptInterpreter::LanguageToString (lldb::ScriptLanguage language)
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

View File

@ -34,6 +34,7 @@ using namespace lldb_private;
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 @@ ScriptInterpreterPython::ExportFunctionDefinitionToInterpreter (StringList &func
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 @@ ScriptInterpreterPython::GenerateBreakpointCommandCallbackData (StringList &user
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 @@ ScriptInterpreterPython::RunEmbeddedPythonInterpreter (lldb::thread_arg_t baton)
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

View File

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

View File

@ -0,0 +1,5 @@
LEVEL = ../../../make
CXX_SOURCES := main.cpp
include $(LEVEL)/Makefile.rules

View File

@ -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()

View File

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

View File

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