forked from OSchip/llvm-project
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:
parent
c591f3afc3
commit
0c5ef693a2
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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)"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
LEVEL = ../../../make
|
||||
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include $(LEVEL)/Makefile.rules
|
|
@ -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()
|
|
@ -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.
|
||||
}
|
Loading…
Reference in New Issue