Some descriptive text for the Python script feature:

- help type summary add now gives some hints on how to use it
frame variable and target variable now have a --no-summary-depth (-Y) option:
 - simply using -Y without an argument will skip one level of summaries, i.e.
   your aggregate types will expand their children and display no summary, even
   if they have one. children will behave normally
 - using -Y<int>, as in -Y4, -Y7, ..., will skip as many levels of summaries as
   given by the <int> parameter (obviously, -Y and -Y1 are the same thing). children
   beneath the given depth level will behave normally
 -Y0 is the same as omitting the --no-summary-depth parameter entirely
 This option replaces the defined-but-unimplemented --no-summary

llvm-svn: 135336
This commit is contained in:
Enrico Granata 2011-07-16 01:22:04 +00:00
parent c591f3afc3
commit 0c5ef693a2
13 changed files with 287 additions and 21 deletions

View File

@ -593,7 +593,8 @@ public:
bool use_objc,
lldb::DynamicValueType use_dynamic,
bool scope_already_checked,
bool flat_output);
bool flat_output,
uint32_t omit_summary_depth);
// returns true if this is a char* or a char[]
// if it is a char* and check_pointer is true,

View File

@ -47,7 +47,7 @@ public:
OptionParsingStarting (CommandInterpreter &interpreter);
bool show_types;
bool show_summary;
uint32_t no_summary_depth;
bool show_location;
bool flat_output;
bool use_objc;

View File

@ -658,7 +658,8 @@ SBValue::GetDescription (SBStream &description)
use_objc,
use_dynamic,
scope_already_checked,
flat_output);
flat_output,
0);
}
else
description.Printf ("No value");

View File

@ -329,7 +329,8 @@ CommandObjectExpression::EvaluateExpression
m_options.print_object, // Print the objective C object?
use_dynamic,
true, // Scope is already checked. Const results are always in scope.
false); // Don't flatten output
false, // Don't flatten output
0); // Always use summaries (you might want an option --no-summary like there is for frame variable)
if (result)
result->SetStatus (eReturnStatusSuccessFinishResult);
}

View File

@ -501,7 +501,8 @@ public:
m_varobj_options.use_objc,
m_varobj_options.use_dynamic,
false,
m_varobj_options.flat_output);
m_varobj_options.flat_output,
m_varobj_options.no_summary_depth);
}
}
}
@ -552,7 +553,8 @@ public:
m_varobj_options.use_objc,
m_varobj_options.use_dynamic,
false,
m_varobj_options.flat_output);
m_varobj_options.flat_output,
m_varobj_options.no_summary_depth);
}
else
{
@ -642,7 +644,8 @@ public:
m_varobj_options.use_objc,
m_varobj_options.use_dynamic,
false,
m_varobj_options.flat_output);
m_varobj_options.flat_output,
m_varobj_options.no_summary_depth);
}
}
}

View File

@ -658,7 +658,8 @@ public:
m_varobj_options.use_objc,
m_varobj_options.use_dynamic,
scope_already_checked,
m_varobj_options.flat_output);
m_varobj_options.flat_output,
0);
}
else
{

View File

@ -489,7 +489,8 @@ public:
m_varobj_options.use_objc,
m_varobj_options.use_dynamic,
false,
m_varobj_options.flat_output);
m_varobj_options.flat_output,
m_varobj_options.no_summary_depth);
}

View File

@ -1009,6 +1009,18 @@ CommandObject (interpreter,
"\n"
"A command you may definitely want to try if you're doing C++ debugging is:\n"
"type summary add -f \"${var._M_dataplus._M_p}\" std::string\n"
"\n"
"You can also add Python summaries, in which case you will use lldb public API to gather information from your variables"
"and elaborate them to a meaningful summary inside a script written in Python. The variable object will be passed to your"
"script as an SBValue object. The following example might help you when starting to use the Python summaries feature:\n"
"type summary add JustADemo -s \"value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();\"\n"
"If you prefer to type your scripts on multiple lines, you will use the -P option and then type your script, ending it with "
"the word DONE on a line by itself to mark you're finished editing your code:\n"
"(lldb)type summary add JustADemo -P\n"
" value = valobj.GetChildMemberWithName('value');\n"
" return 'My value is ' + value.GetValue();\n"
"DONE\n"
"(lldb)"
);
}

View File

@ -2398,7 +2398,8 @@ ValueObject::DumpValueObject
bool use_objc,
lldb::DynamicValueType use_dynamic,
bool scope_already_checked,
bool flat_output
bool flat_output,
uint32_t omit_summary_depth
)
{
if (valobj)
@ -2458,6 +2459,9 @@ ValueObject::DumpValueObject
const char *sum_cstr = NULL;
SummaryFormat* entry = valobj->GetSummaryFormat().get();
if (omit_summary_depth > 0)
entry = NULL;
if (err_cstr == NULL)
{
val_cstr = valobj->GetValueAsCString();
@ -2474,7 +2478,7 @@ ValueObject::DumpValueObject
if (print_valobj)
{
sum_cstr = valobj->GetSummaryAsCString();
sum_cstr = (omit_summary_depth == 0) ? valobj->GetSummaryAsCString() : NULL;
// We must calculate this value in realtime because entry might alter this variable's value
// (e.g. by saying ${var%fmt}) and render precached values useless
@ -2571,7 +2575,8 @@ ValueObject::DumpValueObject
false,
use_dynamic,
true,
flat_output);
flat_output,
omit_summary_depth > 1 ? omit_summary_depth - 1 : 0);
}
}

View File

@ -38,7 +38,7 @@ g_option_table[] =
{ LLDB_OPT_SET_1, false, "objc", 'O', no_argument, NULL, 0, eArgTypeNone, "Print as an Objective-C object."},
{ LLDB_OPT_SET_1, false, "ptr-depth", 'P', required_argument, NULL, 0, eArgTypeCount, "The number of pointers to be traversed when dumping values (default is zero)."},
{ LLDB_OPT_SET_1, false, "show-types", 'T', no_argument, NULL, 0, eArgTypeNone, "Show variable types when dumping values."},
{ LLDB_OPT_SET_1, false, "no-summary", 'Y', no_argument, NULL, 0, eArgTypeNone, "Omit summary information."},
{ LLDB_OPT_SET_1, false, "no-summary-depth",'Y', optional_argument, NULL, 0, eArgTypeCount, "Set a depth for omitting summary information (default is 1)."},
{ 0, false, NULL, 0, 0, NULL, NULL, eArgTypeNone, NULL }
};
@ -80,7 +80,6 @@ OptionGroupValueObjectDisplay::SetOptionValue (CommandInterpreter &interpreter,
}
break;
case 'T': show_types = true; break;
case 'Y': show_summary = false; break;
case 'L': show_location= true; break;
case 'F': flat_output = true; break;
case 'O': use_objc = true; break;
@ -96,6 +95,17 @@ OptionGroupValueObjectDisplay::SetOptionValue (CommandInterpreter &interpreter,
error.SetErrorStringWithFormat("Invalid pointer depth '%s'.\n", option_arg);
break;
case 'Y':
if (option_arg)
{
no_summary_depth = Args::StringToUInt32 (option_arg, 0, 0, &success);
if (!success)
error.SetErrorStringWithFormat("Invalid pointer depth '%s'.\n", option_arg);
}
else
no_summary_depth = 1;
break;
default:
error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
break;
@ -107,13 +117,13 @@ OptionGroupValueObjectDisplay::SetOptionValue (CommandInterpreter &interpreter,
void
OptionGroupValueObjectDisplay::OptionParsingStarting (CommandInterpreter &interpreter)
{
show_types = false;
show_summary = true;
show_location = false;
flat_output = false;
use_objc = false;
max_depth = UINT32_MAX;
ptr_depth = 0;
show_types = false;
no_summary_depth = 0;
show_location = false;
flat_output = false;
use_objc = false;
max_depth = UINT32_MAX;
ptr_depth = 0;
Target *target = interpreter.GetExecutionContext().target;
if (target != NULL)

View File

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

View File

@ -0,0 +1,169 @@
"""
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-skip-summary")
@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)
# Setup the summaries for this scenario
self.runCmd("type summary add -f \"${var._M_dataplus._M_p}\" std::string") # This works fine on OSX 10.6.8, if it differs on your implementation, submit a patch to adapt it to your C++ stdlib
self.runCmd("type summary add -f \"Level 1\" \"DeepData_1\"")
self.runCmd("type summary add -f \"Level 2\" \"DeepData_2\" -e")
self.runCmd("type summary add -f \"Level 3\" \"DeepData_3\"")
self.runCmd("type summary add -f \"Level 4\" \"DeepData_4\"")
self.runCmd("type summary add -f \"Level 5\" \"DeepData_5\"")
# Default case, just print out summaries
self.expect('frame variable',
substrs = ['(DeepData_1) data1 = Level 1',
'(DeepData_2) data2 = Level 2 {',
'm_child1 = Level 3',
'm_child2 = Level 3',
'm_child3 = Level 3',
'm_child4 = Level 3',
'}'])
# Skip the default (should be 1) levels of summaries
self.expect('frame variable -Y',
substrs = ['(DeepData_1) data1 = {',
'm_child1 = 0x',
'}',
'(DeepData_2) data2 = {',
'm_child1 = Level 3',
'm_child2 = Level 3',
'm_child3 = Level 3',
'm_child4 = Level 3',
'}'])
# Now skip 2 levels of summaries
self.expect('frame variable -Y2',
substrs = ['(DeepData_1) data1 = {',
'm_child1 = 0x',
'}',
'(DeepData_2) data2 = {',
'm_child1 = {',
'm_child1 = 0x',
'Level 4',
'm_child2 = {',
'm_child3 = {',
'}'])
# Check that no "Level 3" comes out
self.expect('frame variable data1.m_child1 -Y2', matching=False,
substrs = ['Level 3'])
# Now expand a pointer with 2 level of skipped summaries
self.expect('frame variable data1.m_child1 -Y2',
substrs = ['(DeepData_2 *) data1.m_child1 = 0x'])
# Deref and expand said pointer
self.expect('frame variable *data1.m_child1 -Y2',
substrs = ['(DeepData_2) *data1.m_child1 = {',
'm_child2 = {',
'm_child1 = 0x',
'Level 4',
'}'])
# Expand an expression, skipping 2 layers of summaries
self.expect('frame variable data1.m_child1->m_child2 -Y2',
substrs = ['(DeepData_3) data1.m_child1->m_child2 = {',
'm_child2 = {',
'm_child1 = Level 5',
'm_child2 = Level 5',
'm_child3 = Level 5',
'}'])
# Expand same expression, skipping only 1 layer of summaries
self.expect('frame variable data1.m_child1->m_child2 -Y1',
substrs = ['(DeepData_3) data1.m_child1->m_child2 = {',
'm_child1 = 0x',
'Level 4',
'm_child2 = Level 4',
'}'])
# Expand same expression, skipping 3 layers of summaries
self.expect('frame variable data1.m_child1->m_child2 -Y3',
substrs = ['(DeepData_3) data1.m_child1->m_child2 = {',
'm_some_text = "Just a test"',
'm_child2 = {',
'm_some_text = "Just a test"'])
# Expand within a standard string (might depend on the implementation of the C++ stdlib you use)
self.expect('frame variable data1.m_child1->m_child2.m_child1.m_child2 -Y2',
substrs = ['(DeepData_5) data1.m_child1->m_child2.m_child1.m_child2 = {',
'm_some_text = {',
'_M_dataplus = {',
'_M_p = 0x',
'"Just a test"'])
# Repeat the above, but only skip 1 level of summaries
self.expect('frame variable data1.m_child1->m_child2.m_child1.m_child2 -Y1',
substrs = ['(DeepData_5) data1.m_child1->m_child2.m_child1.m_child2 = {',
'm_some_text = "Just a test"',
'}'])
# Change summary and expand, first without -Y then with -Y
self.runCmd("type summary add -f \"${var.m_some_text}\" DeepData_5")
self.expect('fr var data2.m_child4.m_child2.m_child2',
substrs = ['(DeepData_5) data2.m_child4.m_child2.m_child2 = "Just a test"'])
self.expect('fr var data2.m_child4.m_child2.m_child2 -Y',
substrs = ['(DeepData_5) data2.m_child4.m_child2.m_child2 = {',
'm_some_text = "Just a test"',
'}'])
if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
atexit.register(lambda: lldb.SBDebugger.Terminate())
unittest2.main()

View File

@ -0,0 +1,57 @@
#include <string>
struct DeepData_5
{
std::string m_some_text;
DeepData_5() :
m_some_text("Just a test") {}
};
struct DeepData_4
{
DeepData_5 m_child1;
DeepData_5 m_child2;
DeepData_5 m_child3;
};
struct DeepData_3
{
DeepData_4& m_child1;
DeepData_4 m_child2;
DeepData_3() : m_child1(* (new DeepData_4())), m_child2(DeepData_4()) {}
};
struct DeepData_2
{
DeepData_3 m_child1;
DeepData_3 m_child2;
DeepData_3 m_child3;
DeepData_3 m_child4;
};
struct DeepData_1
{
DeepData_2 *m_child1;
DeepData_1() :
m_child1(new DeepData_2())
{}
};
/*
type summary add -f "${var._M_dataplus._M_p}" std::string
type summary add -f "Level 1" "DeepData_1"
type summary add -f "Level 2" "DeepData_2" -e
type summary add -f "Level 3" "DeepData_3"
type summary add -f "Level 4" "DeepData_4"
type summary add -f "Level 5" "DeepData_5"
*/
int main()
{
DeepData_1 data1;
DeepData_2 data2;
return 0; // Set break point at this line.
}