forked from OSchip/llvm-project
new detailed descriptions for type summary add and type format add
some changes to the help system code for better display of long help text -p and -r flags now also work for type format add llvm-svn: 134574
This commit is contained in:
parent
2bbdc0bcda
commit
82a7d98342
|
@ -242,6 +242,18 @@ public:
|
|||
const char *separator,
|
||||
const char *help_text,
|
||||
uint32_t max_word_len);
|
||||
|
||||
// this mimics OutputFormattedHelpText but it does perform a much simpler
|
||||
// formatting, basically ensuring line alignment. This is only good if you have
|
||||
// some complicated layout for your help text and want as little help as reasonable
|
||||
// in properly displaying it. Most of the times, you simply want to type some text
|
||||
// and have it printed in a reasonable way on screen. If so, use OutputFormattedHelpText
|
||||
void
|
||||
OutputHelpText (Stream &stream,
|
||||
const char *command_word,
|
||||
const char *separator,
|
||||
const char *help_text,
|
||||
uint32_t max_word_len);
|
||||
|
||||
Debugger &
|
||||
GetDebugger ()
|
||||
|
|
|
@ -29,12 +29,36 @@ public:
|
|||
|
||||
typedef const char *(ArgumentHelpCallbackFunction) ();
|
||||
|
||||
struct ArgumentHelpCallback
|
||||
{
|
||||
ArgumentHelpCallbackFunction *help_callback;
|
||||
bool self_formatting;
|
||||
ArgumentHelpCallback(ArgumentHelpCallbackFunction *p,
|
||||
bool f = false) :
|
||||
help_callback(p),
|
||||
self_formatting(f)
|
||||
{
|
||||
}
|
||||
|
||||
const char*
|
||||
operator () () const
|
||||
{
|
||||
return (*help_callback)();
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return (help_callback != NULL);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct ArgumentTableEntry // Entries in the main argument information table
|
||||
{
|
||||
lldb::CommandArgumentType arg_type;
|
||||
const char *arg_name;
|
||||
CommandCompletions::CommonCompletionTypes completion_type;
|
||||
ArgumentHelpCallbackFunction *help_function;
|
||||
ArgumentHelpCallback help_function;
|
||||
const char *help_text;
|
||||
};
|
||||
|
||||
|
|
|
@ -351,7 +351,6 @@ namespace lldb {
|
|||
eArgTypeExprFormat,
|
||||
eArgTypeFilename,
|
||||
eArgTypeFormat,
|
||||
eArgTypeFormatString,
|
||||
eArgTypeFrameIndex,
|
||||
eArgTypeFullName,
|
||||
eArgTypeFunctionName,
|
||||
|
@ -387,6 +386,7 @@ namespace lldb {
|
|||
eArgTypeSourceFile,
|
||||
eArgTypeSortOrder,
|
||||
eArgTypeStartAddress,
|
||||
eArgTypeSummaryString,
|
||||
eArgTypeSymbol,
|
||||
eArgTypeThreadID,
|
||||
eArgTypeThreadIndex,
|
||||
|
|
|
@ -63,6 +63,12 @@ private:
|
|||
case 'f':
|
||||
error = Args::StringToFormat(option_arg, m_format, NULL);
|
||||
break;
|
||||
case 'p':
|
||||
m_skip_pointers = true;
|
||||
break;
|
||||
case 'r':
|
||||
m_skip_references = true;
|
||||
break;
|
||||
default:
|
||||
error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
|
||||
break;
|
||||
|
@ -76,6 +82,8 @@ private:
|
|||
{
|
||||
m_cascade = true;
|
||||
m_format = eFormatInvalid;
|
||||
m_skip_pointers = false;
|
||||
m_skip_references = false;
|
||||
}
|
||||
|
||||
const OptionDefinition*
|
||||
|
@ -92,6 +100,8 @@ private:
|
|||
|
||||
bool m_cascade;
|
||||
lldb::Format m_format;
|
||||
bool m_skip_references;
|
||||
bool m_skip_pointers;
|
||||
};
|
||||
|
||||
CommandOptions m_options;
|
||||
|
@ -118,6 +128,34 @@ public:
|
|||
type_arg.push_back (type_style_arg);
|
||||
|
||||
m_arguments.push_back (type_arg);
|
||||
|
||||
SetHelpLong(
|
||||
"Some examples of using this command.\n"
|
||||
"We use as reference the following snippet of code:\n"
|
||||
"\n"
|
||||
"typedef int Aint;\n"
|
||||
"typedef float Afloat;\n"
|
||||
"typedef Aint Bint;\n"
|
||||
"typedef Afloat Bfloat;\n"
|
||||
"\n"
|
||||
"Aint ix = 5;\n"
|
||||
"Bint iy = 5;\n"
|
||||
"\n"
|
||||
"Afloat fx = 3.14;\n"
|
||||
"BFloat fy = 3.14;\n"
|
||||
"\n"
|
||||
"Typing:\n"
|
||||
"type format add -f hex AInt\n"
|
||||
"frame variable iy\n"
|
||||
"will produce an hex display of iy, because no formatter is available for Bint and the one for Aint is used instead\n"
|
||||
"To prevent this type\n"
|
||||
"type format add -f hex -C no AInt\n"
|
||||
"\n"
|
||||
"A similar reasoning applies to\n"
|
||||
"type format add -f hex -C no float -p\n"
|
||||
"which now prints all floats and float&s as hexadecimal, but does not format float*s\n"
|
||||
"and does not change the default display for Afloat and Bfloat objects.\n"
|
||||
);
|
||||
}
|
||||
|
||||
~CommandObjectTypeFormatAdd ()
|
||||
|
@ -145,7 +183,10 @@ public:
|
|||
|
||||
ValueFormatSP entry;
|
||||
|
||||
entry.reset(new ValueFormat(m_options.m_format,m_options.m_cascade));
|
||||
entry.reset(new ValueFormat(m_options.m_format,
|
||||
m_options.m_cascade,
|
||||
m_options.m_skip_pointers,
|
||||
m_options.m_skip_references));
|
||||
|
||||
// now I have a valid format, let's add it to every type
|
||||
|
||||
|
@ -172,6 +213,8 @@ CommandObjectTypeFormatAdd::CommandOptions::g_option_table[] =
|
|||
{
|
||||
{ LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade to derived typedefs."},
|
||||
{ LLDB_OPT_SET_ALL, false, "format", 'f', required_argument, NULL, 0, eArgTypeFormat, "The format to use to display this type."},
|
||||
{ LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', no_argument, NULL, 0, eArgTypeBoolean, "Don't use this format for pointers-to-type objects."},
|
||||
{ LLDB_OPT_SET_ALL, false, "skip-references", 'r', no_argument, NULL, 0, eArgTypeBoolean, "Don't use this format for references-to-type objects."},
|
||||
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
|
||||
};
|
||||
|
||||
|
@ -343,9 +386,11 @@ private:
|
|||
{
|
||||
if (regex == NULL || regex->Execute(type))
|
||||
{
|
||||
result->GetOutputStream().Printf ("%s: %s%s\n", type,
|
||||
result->GetOutputStream().Printf ("%s: %s%s%s%s\n", type,
|
||||
FormatManager::GetFormatAsCString (entry->m_format),
|
||||
entry->m_cascades ? "" : " (not cascading)");
|
||||
entry->m_cascades ? "" : " (not cascading)",
|
||||
entry->m_skip_pointers ? " (skip pointers)" : "",
|
||||
entry->m_skip_references ? " (skip references)" : "");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -489,6 +534,62 @@ public:
|
|||
type_arg.push_back (type_style_arg);
|
||||
|
||||
m_arguments.push_back (type_arg);
|
||||
|
||||
SetHelpLong(
|
||||
"Some examples of using this command.\n"
|
||||
"We use as reference the following snippet of code:\n"
|
||||
"struct JustADemo\n"
|
||||
"{\n"
|
||||
"int* ptr;\n"
|
||||
"float value;\n"
|
||||
"JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {}\n"
|
||||
"};\n"
|
||||
"JustADemo object(42,3.14);\n"
|
||||
"struct AnotherDemo : public JustADemo\n"
|
||||
"{\n"
|
||||
"uint8_t byte;\n"
|
||||
"AnotherDemo(uint8_t b = 'E', int p = 1, float v = 0.1) : JustADemo(p,v), byte(b) {}\n"
|
||||
"};\n"
|
||||
"AnotherDemo *another_object = new AnotherDemo('E',42,3.14);\n"
|
||||
"\n"
|
||||
"type summary add -f \"the answer is ${*var.ptr}\" JustADemo\n"
|
||||
"when typing frame variable object you will get \"the answer is 42\"\n"
|
||||
"type summary add -f \"the answer is ${*var.ptr}, and the question is ${var.value}\" JustADemo\n"
|
||||
"when typing frame variable object you will get \"the answer is 42 and the question is 3.14\"\n"
|
||||
"\n"
|
||||
"Alternatively, you could also say\n"
|
||||
"type summary add -f \"${var%V} -> ${*var}\" \"int *\"\n"
|
||||
"and replace the above summary string with\n"
|
||||
"type summary add -f \"the answer is ${var.ptr}, and the question is ${var.value}\" JustADemo\n"
|
||||
"to obtain a similar result\n"
|
||||
"\n"
|
||||
"To add a summary valid for both JustADemo and AnotherDemo you can use the scoping operator, as in:\n"
|
||||
"type summary add -f \"${var.ptr}, ${var.value},{${var.byte}}\" JustADemo -C yes\n"
|
||||
"\n"
|
||||
"This will be used for both variables of type JustADemo and AnotherDemo. To prevent this, change the -C to read -C no\n"
|
||||
"If you do not want pointers to be shown using that summary, you can use the -p option, as in:\n"
|
||||
"type summary add -f \"${var.ptr}, ${var.value},{${var.byte}}\" JustADemo -C yes -p\n"
|
||||
"A similar option -r exists for references.\n"
|
||||
"\n"
|
||||
"If you simply want a one-line summary of the content of your variable, without typing an explicit string to that effect\n"
|
||||
"you can use the -c option, without giving any summary string:\n"
|
||||
"type summary add -c JustADemo\n"
|
||||
"frame variable object\n"
|
||||
"the output being similar to (ptr=0xsomeaddress, value=3.14)\n"
|
||||
"\n"
|
||||
"If you want to display some summary text, but also expand the structure of your object, you can add the -e option, as in:\n"
|
||||
"type summary add -e -f \"*ptr = ${*var.ptr}\" JustADemo\n"
|
||||
"Here the value of the int* is displayed, followed by the standard LLDB sequence of children objects, one per line.\n"
|
||||
"to get an output like:\n"
|
||||
"\n"
|
||||
"*ptr = 42 {\n"
|
||||
" ptr = 0xsomeaddress\n"
|
||||
" value = 3.14\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"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"
|
||||
);
|
||||
}
|
||||
|
||||
~CommandObjectTypeSummaryAdd ()
|
||||
|
@ -574,7 +675,7 @@ CommandObjectTypeSummaryAdd::CommandOptions::g_option_table[] =
|
|||
{ LLDB_OPT_SET_ALL, false, "skip-references", 'r', no_argument, NULL, 0, eArgTypeBoolean, "Don't use this format for references-to-type objects."},
|
||||
{ LLDB_OPT_SET_ALL, false, "regex", 'x', no_argument, NULL, 0, eArgTypeBoolean, "Type names are actually regular expressions."},
|
||||
{ LLDB_OPT_SET_1 , true, "inline-children", 'c', no_argument, NULL, 0, eArgTypeBoolean, "If true, inline all child values into summary string."},
|
||||
{ LLDB_OPT_SET_2 , true, "format-string", 'f', required_argument, NULL, 0, eArgTypeFormatString, "Format string used to display text and object contents."},
|
||||
{ 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."},
|
||||
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
|
||||
};
|
||||
|
|
|
@ -2013,6 +2013,49 @@ CommandInterpreter::OutputFormattedHelpText (Stream &strm,
|
|||
strm.IndentLess(indent_size);
|
||||
}
|
||||
|
||||
void
|
||||
CommandInterpreter::OutputHelpText (Stream &strm,
|
||||
const char *word_text,
|
||||
const char *separator,
|
||||
const char *help_text,
|
||||
uint32_t max_word_len)
|
||||
{
|
||||
int indent_size = max_word_len + strlen (separator) + 2;
|
||||
|
||||
strm.IndentMore (indent_size);
|
||||
|
||||
StreamString text_strm;
|
||||
text_strm.Printf ("%-*s %s %s", max_word_len, word_text, separator, help_text);
|
||||
|
||||
const uint32_t max_columns = m_debugger.GetTerminalWidth();
|
||||
bool first_line = true;
|
||||
|
||||
size_t len = text_strm.GetSize();
|
||||
const char *text = text_strm.GetData();
|
||||
|
||||
uint32_t chars_left = max_columns;
|
||||
|
||||
for (uint32_t i = 0; i < len; i++)
|
||||
{
|
||||
if ((text[i] == ' ' && ::strchr((text+i+1), ' ') && chars_left < ::strchr((text+i+1), ' ')-(text+i)) || text[i] == '\n')
|
||||
{
|
||||
first_line = false;
|
||||
chars_left = max_columns - indent_size;
|
||||
strm.EOL();
|
||||
strm.Indent();
|
||||
}
|
||||
else
|
||||
{
|
||||
strm.PutChar(text[i]);
|
||||
chars_left--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
strm.EOL();
|
||||
strm.IndentLess(indent_size);
|
||||
}
|
||||
|
||||
void
|
||||
CommandInterpreter::AproposAllSubCommands (CommandObject *cmd_obj, const char *prefix, const char *search_word,
|
||||
StringList &commands_found, StringList &commands_help)
|
||||
|
|
|
@ -469,9 +469,20 @@ CommandObject::GetArgumentHelp (Stream &str, CommandArgumentType arg_type, Comma
|
|||
StreamString name_str;
|
||||
name_str.Printf ("<%s>", entry->arg_name);
|
||||
|
||||
if (entry->help_function != NULL)
|
||||
interpreter.OutputFormattedHelpText (str, name_str.GetData(), "--", (*(entry->help_function)) (),
|
||||
name_str.GetSize());
|
||||
if (entry->help_function)
|
||||
{
|
||||
const char* help_text = entry->help_function();
|
||||
if (!entry->help_function.self_formatting)
|
||||
{
|
||||
interpreter.OutputFormattedHelpText (str, name_str.GetData(), "--", help_text,
|
||||
name_str.GetSize());
|
||||
}
|
||||
else
|
||||
{
|
||||
interpreter.OutputHelpText(str, name_str.GetData(), "--", help_text,
|
||||
name_str.GetSize());
|
||||
}
|
||||
}
|
||||
else
|
||||
interpreter.OutputFormattedHelpText (str, name_str.GetData(), "--", entry->help_text, name_str.GetSize());
|
||||
}
|
||||
|
@ -630,32 +641,61 @@ BreakpointIDRangeHelpTextCallback ()
|
|||
static const char *
|
||||
FormatHelpTextCallback ()
|
||||
{
|
||||
|
||||
static char* help_text_ptr = NULL;
|
||||
|
||||
if (help_text_ptr)
|
||||
return help_text_ptr;
|
||||
|
||||
StreamString sstr;
|
||||
sstr << "One of the format names (or one-character names) that can be used to show a variable's value:\n";
|
||||
for (Format f = eFormatDefault; f < kNumFormats; f = Format(f+1))
|
||||
{
|
||||
if (f != eFormatDefault)
|
||||
sstr.PutChar('\n');
|
||||
|
||||
char format_char = FormatManager::GetFormatAsFormatChar(f);
|
||||
if (format_char)
|
||||
sstr.Printf("'%c' or ", format_char);
|
||||
|
||||
sstr.Printf ("\"%s\" ; ", FormatManager::GetFormatAsCString(f));
|
||||
sstr.Printf ("\"%s\"", FormatManager::GetFormatAsCString(f));
|
||||
}
|
||||
|
||||
sstr.Flush();
|
||||
|
||||
std::string data = sstr.GetString();
|
||||
|
||||
char* help = new char[data.length()+1];
|
||||
help_text_ptr = new char[data.length()+1];
|
||||
|
||||
data.copy(help, data.length());
|
||||
data.copy(help_text_ptr, data.length());
|
||||
|
||||
return help;
|
||||
return help_text_ptr;
|
||||
}
|
||||
|
||||
static const char *
|
||||
FormatStringHelpTextCallback()
|
||||
SummaryStringHelpTextCallback()
|
||||
{
|
||||
return "Ask me tomorrow";
|
||||
return
|
||||
"A summary string is a way to extract information from variables in order to present them using a summary.\n"
|
||||
"Summary strings contain static text, variables, scopes and control sequences:\n"
|
||||
" - Static text can be any sequence of non-special characters, i.e. anything but '{', '}', '$', or '\\'.\n"
|
||||
" - Variables are sequences of characters beginning with ${, ending with } and that contain symbols in the format described below.\n"
|
||||
" - Scopes are any sequence of text between { and }. Anything included in a scope will only appear in the output summary if there were no errors.\n"
|
||||
" - Control sequences are the usual C/C++ '\\a', '\\n', ..., plus '\\$', '\\{' and '\\}'.\n"
|
||||
"A summary string works by copying static text verbatim, turning control sequences into their character counterpart, expanding variables and trying to expand scopes.\n"
|
||||
"A variable is expanded by giving it a value other than its textual representation, and the way this is done depends on what comes after the ${ marker.\n"
|
||||
"The most common sequence if ${var followed by an expression path, which is the text one would type to access a member of an aggregate types, given a variable of that type"
|
||||
" (e.g. if type T has a member named x, which has a member named y, and if t is of type T, the expression path would be .x.y and the way to fit that into a summary string would be"
|
||||
" ${var.x.y}). In expression paths you can use either . or -> without any difference in meaning. You can also use ${*var followed by an expression path and in that case"
|
||||
" the object referred by the path will be dereferenced before being displayed. If the object is not a pointer, doing so will cause an error.\n"
|
||||
"By default, summary strings attempt to display the summary for any variable they reference, and if that fails the value. If neither can be shown, nothing is displayed."
|
||||
"In a summary string, you can also use an array index [n], or a slice-like range [n-m]. This can have two different meanings depending on what kind of object the expression"
|
||||
" path refers to:\n"
|
||||
" - if it is a scalar type (any basic type like int, float, ...) the expression is a bitfield, i.e. the bits indicated by the indexing operator are extracted out of the number"
|
||||
" and displayed as an individual variable\n"
|
||||
" - if it is an array or pointer the array items indicated by the indexing operator are shown as the result of the variable. if the expression is an array, real array items are"
|
||||
" printed; if it is a pointer, the pointer-as-array syntax is used to obtain the values (this means, the latter case can have no range checking)\n"
|
||||
"If you are trying to display an array for which the size is known, you can also use [] instead of giving an exact range. This has the effect of showing items 0 thru size - 1.";
|
||||
}
|
||||
|
||||
const char *
|
||||
|
@ -693,8 +733,7 @@ CommandObject::g_arguments_data[] =
|
|||
{ eArgTypeExpression, "expr", CommandCompletions::eNoCompletion, NULL, "Help text goes here." },
|
||||
{ eArgTypeExprFormat, "expression-format", CommandCompletions::eNoCompletion, NULL, "[ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ]" },
|
||||
{ eArgTypeFilename, "filename", CommandCompletions::eDiskFileCompletion, NULL, "The name of a file (can include path)." },
|
||||
{ eArgTypeFormat, "format", CommandCompletions::eNoCompletion, FormatHelpTextCallback, NULL },
|
||||
{ eArgTypeFormatString, "format-string", CommandCompletions::eNoCompletion, FormatStringHelpTextCallback, NULL },
|
||||
{ eArgTypeFormat, "format", CommandCompletions::eNoCompletion, CommandObject::ArgumentHelpCallback(FormatHelpTextCallback, true), NULL },
|
||||
{ eArgTypeFrameIndex, "frame-index", CommandCompletions::eNoCompletion, NULL, "Index into a thread's list of frames." },
|
||||
{ eArgTypeFullName, "fullname", CommandCompletions::eNoCompletion, NULL, "Help text goes here." },
|
||||
{ eArgTypeFunctionName, "function-name", CommandCompletions::eNoCompletion, NULL, "The name of a function." },
|
||||
|
@ -730,6 +769,7 @@ CommandObject::g_arguments_data[] =
|
|||
{ eArgTypeSourceFile, "source-file", CommandCompletions::eSourceFileCompletion, NULL, "The name of a source file.." },
|
||||
{ eArgTypeSortOrder, "sort-order", CommandCompletions::eNoCompletion, NULL, "Specify a sort order when dumping lists." },
|
||||
{ eArgTypeStartAddress, "start-address", CommandCompletions::eNoCompletion, NULL, "Help text goes here." },
|
||||
{ eArgTypeSummaryString, "summary-string", CommandCompletions::eNoCompletion, CommandObject::ArgumentHelpCallback(SummaryStringHelpTextCallback, true), NULL },
|
||||
{ eArgTypeSymbol, "symbol", CommandCompletions::eSymbolCompletion, NULL, "Any symbol name (function name, variable, argument, etc.)" },
|
||||
{ eArgTypeThreadID, "thread-id", CommandCompletions::eNoCompletion, NULL, "Thread ID number." },
|
||||
{ eArgTypeThreadIndex, "thread-index", CommandCompletions::eNoCompletion, NULL, "Index into the process' list of threads." },
|
||||
|
|
Loading…
Reference in New Issue