diff options
author | Greg Clayton <gclayton@apple.com> | 2015-02-04 22:00:53 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2015-02-04 22:00:53 +0000 |
commit | 554f68d385920c45c723d97686fe2fbe257e4e0e (patch) | |
tree | 71f037f3a9801d03733dbe048c9081b23b76295f /lldb/source/Core/Debugger.cpp | |
parent | 39b10c2cbb8fb1d4604697c79365c7c582de229b (diff) | |
download | bcm5719-llvm-554f68d385920c45c723d97686fe2fbe257e4e0e.tar.gz bcm5719-llvm-554f68d385920c45c723d97686fe2fbe257e4e0e.zip |
Get rid of Debugger::FormatPrompt() and replace it with the new FormatEntity class.
Why? Debugger::FormatPrompt() would run through the format prompt every time and parse it and emit it piece by piece. It also did formatting differently depending on which key/value pair it was parsing.
The new code improves on this with the following features:
1 - Allow format strings to be parsed into a FormatEntity::Entry which can contain multiple child FormatEntity::Entry objects. This FormatEntity::Entry is a parsed version of what was previously always done in Debugger::FormatPrompt() so it is more efficient to emit formatted strings using the new parsed FormatEntity::Entry.
2 - Allows errors in format strings to be shown immediately when setting the settings (frame-format, thread-format, disassembly-format
3 - Allows auto completion by implementing a new OptionValueFormatEntity and switching frame-format, thread-format, and disassembly-format settings over to using it.
4 - The FormatEntity::Entry for each of the frame-format, thread-format, disassembly-format settings only replaces the old one if the format parses correctly
5 - Combines all consecutive string values together for efficient output. This means all "${ansi.*}" keys and all desensitized characters like "\n" "\t" "\0721" "\x23" will get combined with their previous strings
6 - ${*.script:} (like "${var.script:mymodule.my_var_function}") have all been switched over to use ${script.*:} "${script.var:mymodule.my_var_function}") to make the format easier to parse as I don't believe anyone was using these format string power user features.
7 - All key values pairs are defined in simple C arrays of entries so it is much easier to add new entries.
These changes pave the way for subsequent modifications where we can modify formats to do more (like control the width of value strings can do more and add more functionality more easily like string formatting to control the width, printf formats and more).
llvm-svn: 228207
Diffstat (limited to 'lldb/source/Core/Debugger.cpp')
-rw-r--r-- | lldb/source/Core/Debugger.cpp | 1738 |
1 files changed, 36 insertions, 1702 deletions
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 8466158307a..f25a3f41825 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/StringRef.h" #include "lldb/lldb-private.h" +#include "lldb/Core/FormatEntity.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/RegisterValue.h" @@ -130,24 +131,23 @@ g_language_enumerators[] = static PropertyDefinition g_properties[] = { -{ "auto-confirm", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true all confirmation prompts will receive their default reply." }, -{ "disassembly-format", OptionValue::eTypeString , true, 0 , DEFAULT_DISASSEMBLY_FORMAT, NULL, "The default disassembly format string to use when disassembling instruction sequences." }, -{ "frame-format", OptionValue::eTypeString , true, 0 , DEFAULT_FRAME_FORMAT, NULL, "The default frame format string to use when displaying stack frame information for threads." }, -{ "notify-void", OptionValue::eTypeBoolean, true, false, NULL, NULL, "Notify the user explicitly if an expression returns void (default: false)." }, -{ "prompt", OptionValue::eTypeString , true, OptionValueString::eOptionEncodeCharacterEscapeSequences, "(lldb) ", NULL, "The debugger command line prompt displayed for the user." }, -{ "script-lang", OptionValue::eTypeEnum , true, eScriptLanguagePython, NULL, g_language_enumerators, "The script language to be used for evaluating user-written scripts." }, -{ "stop-disassembly-count", OptionValue::eTypeSInt64 , true, 4 , NULL, NULL, "The number of disassembly lines to show when displaying a stopped context." }, -{ "stop-disassembly-display", OptionValue::eTypeEnum , true, Debugger::eStopDisassemblyTypeNoSource, NULL, g_show_disassembly_enum_values, "Control when to display disassembly when displaying a stopped context." }, -{ "stop-line-count-after", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come after the current source line when displaying a stopped context." }, -{ "stop-line-count-before", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come before the current source line when displaying a stopped context." }, -{ "term-width", OptionValue::eTypeSInt64 , true, 80 , NULL, NULL, "The maximum number of columns to use for displaying text." }, -{ "thread-format", OptionValue::eTypeString , true, 0 , DEFAULT_THREAD_FORMAT, NULL, "The default thread format string to use when displaying thread information." }, -{ "use-external-editor", OptionValue::eTypeBoolean, true, false, NULL, NULL, "Whether to use an external editor or not." }, -{ "use-color", OptionValue::eTypeBoolean, true, true , NULL, NULL, "Whether to use Ansi color codes or not." }, -{ "auto-one-line-summaries", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will automatically display small structs in one-liner format (default: true)." }, -{ "escape-non-printables", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will automatically escape non-printable and escape characters when formatting strings." }, - - { NULL, OptionValue::eTypeInvalid, true, 0 , NULL, NULL, NULL } +{ "auto-confirm", OptionValue::eTypeBoolean , true, false, NULL, NULL, "If true all confirmation prompts will receive their default reply." }, +{ "disassembly-format", OptionValue::eTypeFormatEntity, true, 0 , DEFAULT_DISASSEMBLY_FORMAT, NULL, "The default disassembly format string to use when disassembling instruction sequences." }, +{ "frame-format", OptionValue::eTypeFormatEntity, true, 0 , DEFAULT_FRAME_FORMAT, NULL, "The default frame format string to use when displaying stack frame information for threads." }, +{ "notify-void", OptionValue::eTypeBoolean , true, false, NULL, NULL, "Notify the user explicitly if an expression returns void (default: false)." }, +{ "prompt", OptionValue::eTypeString , true, OptionValueString::eOptionEncodeCharacterEscapeSequences, "(lldb) ", NULL, "The debugger command line prompt displayed for the user." }, +{ "script-lang", OptionValue::eTypeEnum , true, eScriptLanguagePython, NULL, g_language_enumerators, "The script language to be used for evaluating user-written scripts." }, +{ "stop-disassembly-count", OptionValue::eTypeSInt64 , true, 4 , NULL, NULL, "The number of disassembly lines to show when displaying a stopped context." }, +{ "stop-disassembly-display", OptionValue::eTypeEnum , true, Debugger::eStopDisassemblyTypeNoSource, NULL, g_show_disassembly_enum_values, "Control when to display disassembly when displaying a stopped context." }, +{ "stop-line-count-after", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come after the current source line when displaying a stopped context." }, +{ "stop-line-count-before", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come before the current source line when displaying a stopped context." }, +{ "term-width", OptionValue::eTypeSInt64 , true, 80 , NULL, NULL, "The maximum number of columns to use for displaying text." }, +{ "thread-format", OptionValue::eTypeFormatEntity, true, 0 , DEFAULT_THREAD_FORMAT, NULL, "The default thread format string to use when displaying thread information." }, +{ "use-external-editor", OptionValue::eTypeBoolean , true, false, NULL, NULL, "Whether to use an external editor or not." }, +{ "use-color", OptionValue::eTypeBoolean , true, true , NULL, NULL, "Whether to use Ansi color codes or not." }, +{ "auto-one-line-summaries", OptionValue::eTypeBoolean , true, true, NULL, NULL, "If true, LLDB will automatically display small structs in one-liner format (default: true)." }, +{ "escape-non-printables", OptionValue::eTypeBoolean , true, true, NULL, NULL, "If true, LLDB will automatically escape non-printable and escape characters when formatting strings." }, +{ NULL, OptionValue::eTypeInvalid , true, 0 , NULL, NULL, NULL } }; enum @@ -242,18 +242,18 @@ Debugger::GetAutoConfirm () const return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); } -const char * +const FormatEntity::Entry * Debugger::GetDisassemblyFormat() const { const uint32_t idx = ePropertyDisassemblyFormat; - return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value); + return m_collection_sp->GetPropertyAtIndexAsFormatEntity(NULL, idx); } -const char * +const FormatEntity::Entry * Debugger::GetFrameFormat() const { const uint32_t idx = ePropertyFrameFormat; - return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value); + return m_collection_sp->GetPropertyAtIndexAsFormatEntity(NULL, idx); } bool @@ -282,11 +282,11 @@ Debugger::SetPrompt(const char *p) GetCommandInterpreter().UpdatePrompt(new_prompt); } -const char * +const FormatEntity::Entry * Debugger::GetThreadFormat() const { const uint32_t idx = ePropertyThreadFormat; - return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value); + return m_collection_sp->GetPropertyAtIndexAsFormatEntity(NULL, idx); } lldb::ScriptLanguage @@ -1226,1691 +1226,25 @@ TestPromptFormats (StackFrame *frame) } #endif -static bool -ScanFormatDescriptor (const char* var_name_begin, - const char* var_name_end, - const char** var_name_final, - const char** percent_position, - Format* custom_format, - ValueObject::ValueObjectRepresentationStyle* val_obj_display) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); - *percent_position = ::strchr(var_name_begin,'%'); - if (!*percent_position || *percent_position > var_name_end) - { - if (log) - log->Printf("[ScanFormatDescriptor] no format descriptor in string, skipping"); - *var_name_final = var_name_end; - } - else - { - *var_name_final = *percent_position; - std::string format_name(*var_name_final+1, var_name_end-*var_name_final-1); - if (log) - log->Printf("[ScanFormatDescriptor] parsing %s as a format descriptor", format_name.c_str()); - if ( !FormatManager::GetFormatFromCString(format_name.c_str(), - true, - *custom_format) ) - { - if (log) - log->Printf("[ScanFormatDescriptor] %s is an unknown format", format_name.c_str()); - - switch (format_name.front()) - { - case '@': // if this is an @ sign, print ObjC description - *val_obj_display = ValueObject::eValueObjectRepresentationStyleLanguageSpecific; - break; - case 'V': // if this is a V, print the value using the default format - *val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; - break; - case 'L': // if this is an L, print the location of the value - *val_obj_display = ValueObject::eValueObjectRepresentationStyleLocation; - break; - case 'S': // if this is an S, print the summary after all - *val_obj_display = ValueObject::eValueObjectRepresentationStyleSummary; - break; - case '#': // if this is a '#', print the number of children - *val_obj_display = ValueObject::eValueObjectRepresentationStyleChildrenCount; - break; - case 'T': // if this is a 'T', print the type - *val_obj_display = ValueObject::eValueObjectRepresentationStyleType; - break; - case 'N': // if this is a 'N', print the name - *val_obj_display = ValueObject::eValueObjectRepresentationStyleName; - break; - case '>': // if this is a '>', print the name - *val_obj_display = ValueObject::eValueObjectRepresentationStyleExpressionPath; - break; - default: - if (log) - log->Printf("ScanFormatDescriptor] %s is an error, leaving the previous value alone", format_name.c_str()); - break; - } - } - // a good custom format tells us to print the value using it - else - { - if (log) - log->Printf("[ScanFormatDescriptor] will display value for this VO"); - *val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; - } - } - if (log) - log->Printf("[ScanFormatDescriptor] final format description outcome: custom_format = %d, val_obj_display = %d", - *custom_format, - *val_obj_display); - return true; -} - -static bool -ScanBracketedRange (const char* var_name_begin, - const char* var_name_end, - const char* var_name_final, - const char** open_bracket_position, - const char** separator_position, - const char** close_bracket_position, - const char** var_name_final_if_array_range, - int64_t* index_lower, - int64_t* index_higher) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); - *open_bracket_position = ::strchr(var_name_begin,'['); - if (*open_bracket_position && *open_bracket_position < var_name_final) - { - *separator_position = ::strchr(*open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield - *close_bracket_position = ::strchr(*open_bracket_position,']'); - // as usual, we assume that [] will come before % - //printf("trying to expand a []\n"); - *var_name_final_if_array_range = *open_bracket_position; - if (*close_bracket_position - *open_bracket_position == 1) - { - if (log) - log->Printf("[ScanBracketedRange] '[]' detected.. going from 0 to end of data"); - *index_lower = 0; - } - else if (*separator_position == NULL || *separator_position > var_name_end) - { - char *end = NULL; - *index_lower = ::strtoul (*open_bracket_position+1, &end, 0); - *index_higher = *index_lower; - if (log) - log->Printf("[ScanBracketedRange] [%" PRId64 "] detected, high index is same", *index_lower); - } - else if (*close_bracket_position && *close_bracket_position < var_name_end) - { - char *end = NULL; - *index_lower = ::strtoul (*open_bracket_position+1, &end, 0); - *index_higher = ::strtoul (*separator_position+1, &end, 0); - if (log) - log->Printf("[ScanBracketedRange] [%" PRId64 "-%" PRId64 "] detected", *index_lower, *index_higher); - } - else - { - if (log) - log->Printf("[ScanBracketedRange] expression is erroneous, cannot extract indices out of it"); - return false; - } - if (*index_lower > *index_higher && *index_higher > 0) - { - if (log) - log->Printf("[ScanBracketedRange] swapping indices"); - int64_t temp = *index_lower; - *index_lower = *index_higher; - *index_higher = temp; - } - } - else if (log) - log->Printf("[ScanBracketedRange] no bracketed range, skipping entirely"); - return true; -} - -template <typename T> -static bool RunScriptFormatKeyword(Stream &s, ScriptInterpreter *script_interpreter, T t, const std::string& script_name) -{ - if (script_interpreter) - { - Error script_error; - std::string script_output; - - if (script_interpreter->RunScriptFormatKeyword(script_name.c_str(), t, script_output, script_error) && script_error.Success()) - { - s.Printf("%s", script_output.c_str()); - return true; - } - else - { - s.Printf("<error: %s>",script_error.AsCString()); - } - } - return false; -} - -static ValueObjectSP -ExpandIndexedExpression (ValueObject* valobj, - size_t index, - StackFrame* frame, - bool deref_pointer) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); - const char* ptr_deref_format = "[%d]"; - std::string ptr_deref_buffer(10,0); - ::sprintf(&ptr_deref_buffer[0], ptr_deref_format, index); - if (log) - log->Printf("[ExpandIndexedExpression] name to deref: %s",ptr_deref_buffer.c_str()); - const char* first_unparsed; - ValueObject::GetValueForExpressionPathOptions options; - ValueObject::ExpressionPathEndResultType final_value_type; - ValueObject::ExpressionPathScanEndReason reason_to_stop; - ValueObject::ExpressionPathAftermath what_next = (deref_pointer ? ValueObject::eExpressionPathAftermathDereference : ValueObject::eExpressionPathAftermathNothing); - ValueObjectSP item = valobj->GetValueForExpressionPath (ptr_deref_buffer.c_str(), - &first_unparsed, - &reason_to_stop, - &final_value_type, - options, - &what_next); - if (!item) - { - if (log) - log->Printf("[ExpandIndexedExpression] ERROR: unparsed portion = %s, why stopping = %d," - " final_value_type %d", - first_unparsed, reason_to_stop, final_value_type); - } - else - { - if (log) - log->Printf("[ExpandIndexedExpression] ALL RIGHT: unparsed portion = %s, why stopping = %d," - " final_value_type %d", - first_unparsed, reason_to_stop, final_value_type); - } - return item; -} - -static inline bool -IsToken(const char *var_name_begin, const char *var) -{ - return (::strncmp (var_name_begin, var, strlen(var)) == 0); -} - -static bool -IsTokenWithFormat(const char *var_name_begin, const char *var, std::string &format, const char *default_format, - const ExecutionContext *exe_ctx_ptr, const SymbolContext *sc_ptr) -{ - int var_len = strlen(var); - if (::strncmp (var_name_begin, var, var_len) == 0) - { - var_name_begin += var_len; - if (*var_name_begin == '}') - { - format = default_format; - return true; - } - else if (*var_name_begin == '%') - { - // Allow format specifiers: x|X|u with optional width specifiers. - // ${thread.id%x} ; hex - // ${thread.id%X} ; uppercase hex - // ${thread.id%u} ; unsigned decimal - // ${thread.id%8.8X} ; width.precision + specifier - // ${thread.id%tid} ; unsigned on FreeBSD/Linux, otherwise default_format (0x%4.4x for thread.id) - int dot_count = 0; - const char *specifier = NULL; - int width_precision_length = 0; - const char *width_precision = ++var_name_begin; - while (isdigit(*var_name_begin) || *var_name_begin == '.') - { - dot_count += (*var_name_begin == '.'); - if (dot_count > 1) - break; - var_name_begin++; - width_precision_length++; - } - - if (IsToken (var_name_begin, "tid}")) - { - Target *target = Target::GetTargetFromContexts (exe_ctx_ptr, sc_ptr); - if (target) - { - ArchSpec arch (target->GetArchitecture ()); - llvm::Triple::OSType ostype = arch.IsValid() ? arch.GetTriple().getOS() : llvm::Triple::UnknownOS; - if ((ostype == llvm::Triple::FreeBSD) || (ostype == llvm::Triple::Linux)) - specifier = PRIu64; - } - if (!specifier) - { - format = default_format; - return true; - } - } - else if (IsToken (var_name_begin, "x}")) - specifier = PRIx64; - else if (IsToken (var_name_begin, "X}")) - specifier = PRIX64; - else if (IsToken (var_name_begin, "u}")) - specifier = PRIu64; - - if (specifier) - { - format = "%"; - if (width_precision_length) - format += std::string(width_precision, width_precision_length); - format += specifier; - return true; - } - } - } - return false; -} - -// Find information for the "thread.info.*" specifiers in a format string -static bool -FormatThreadExtendedInfoRecurse -( - const char *var_name_begin, - StructuredData::ObjectSP thread_info_dictionary, - const SymbolContext *sc, - const ExecutionContext *exe_ctx, - Stream &s -) -{ - bool var_success = false; - std::string token_format; - - llvm::StringRef var_name(var_name_begin); - size_t percent_idx = var_name.find('%'); - size_t close_curly_idx = var_name.find('}'); - llvm::StringRef path = var_name; - llvm::StringRef formatter = var_name; - - // 'path' will be the dot separated list of objects to transverse up until we hit - // a close curly brace, a percent sign, or an end of string. - if (percent_idx != llvm::StringRef::npos || close_curly_idx != llvm::StringRef::npos) - { - if (percent_idx != llvm::StringRef::npos && close_curly_idx != llvm::StringRef::npos) - { - if (percent_idx < close_curly_idx) - { - path = var_name.slice(0, percent_idx); - formatter = var_name.substr (percent_idx); - } - else - { - path = var_name.slice(0, close_curly_idx); - formatter = var_name.substr (close_curly_idx); - } - } - else if (percent_idx != llvm::StringRef::npos) - { - path = var_name.slice(0, percent_idx); - formatter = var_name.substr (percent_idx); - } - else if (close_curly_idx != llvm::StringRef::npos) - { - path = var_name.slice(0, close_curly_idx); - formatter = var_name.substr (close_curly_idx); - } - } - - StructuredData::ObjectSP value = thread_info_dictionary->GetObjectForDotSeparatedPath (path); - - if (value.get()) - { - if (value->GetType() == StructuredData::Type::eTypeInteger) - { - if (IsTokenWithFormat (formatter.str().c_str(), "", token_format, "0x%4.4" PRIx64, exe_ctx, sc)) - { - s.Printf(token_format.c_str(), value->GetAsInteger()->GetValue()); - var_success = true; - } - } - else if (value->GetType() == StructuredData::Type::eTypeFloat) - { - s.Printf ("%f", value->GetAsFloat()->GetValue()); - var_success = true; - } - else if (value->GetType() == StructuredData::Type::eTypeString) - { - s.Printf("%s", value->GetAsString()->GetValue().c_str()); - var_success = true; - } - else if (value->GetType() == StructuredData::Type::eTypeArray) - { - if (value->GetAsArray()->GetSize() > 0) - { - s.Printf ("%zu", value->GetAsArray()->GetSize()); - var_success = true; - } - } - else if (value->GetType() == StructuredData::Type::eTypeDictionary) - { - s.Printf ("%zu", value->GetAsDictionary()->GetKeys()->GetAsArray()->GetSize()); - var_success = true; - } - } - - return var_success; -} - - -static bool -FormatPromptRecurse -( - const char *format, - const SymbolContext *sc, - const ExecutionContext *exe_ctx, - const Address *addr, - Stream &s, - const char **end, - ValueObject* valobj, - bool function_changed, - bool initial_function -) -{ - ValueObject* realvalobj = NULL; // makes it super-easy to parse pointers - bool success = true; - const char *p; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); - - for (p = format; *p != '\0'; ++p) - { - if (realvalobj) - { - valobj = realvalobj; - realvalobj = NULL; - } - size_t non_special_chars = ::strcspn (p, "${}\\"); - if (non_special_chars > 0) - { - if (success) - s.Write (p, non_special_chars); - p += non_special_chars; - } - - if (*p == '\0') - { - break; - } - else if (*p == '{') - { - // Start a new scope that must have everything it needs if it is to - // to make it into the final output stream "s". If you want to make - // a format that only prints out the function or symbol name if there - // is one in the symbol context you can use: - // "{function =${function.name}}" - // The first '{' starts a new scope that end with the matching '}' at - // the end of the string. The contents "function =${function.name}" - // will then be evaluated and only be output if there is a function - // or symbol with a valid name. - StreamString sub_strm; - - ++p; // Skip the '{' - - if (FormatPromptRecurse (p, sc, exe_ctx, addr, sub_strm, &p, valobj, function_changed, initial_function)) - { - // The stream had all it needed - s.Write(sub_strm.GetData(), sub_strm.GetSize()); - } - if (*p != '}') - { - success = false; - break; - } - } - else if (*p == '}') - { - // End of a enclosing scope - break; - } - else if (*p == '$') - { - // We have a prompt variable to print - ++p; - if (*p == '{') - { - ++p; - const char *var_name_begin = p; - const char *var_name_end = ::strchr (p, '}'); - - if (var_name_end && var_name_begin < var_name_end) - { - // if we have already failed to parse, skip this variable - if (success) - { - const char *cstr = NULL; - std::string token_format; - Address format_addr; - - // normally "addr" means print a raw address but - // "file-addr-or-load-addr" means print a module + file addr if there's no load addr - bool print_file_addr_or_load_addr = false; - bool addr_offset_concrete_func_only = false; - bool addr_offset_print_with_no_padding = false; - bool calculate_format_addr_function_offset = false; - // Set reg_kind and reg_num to invalid values - RegisterKind reg_kind = kNumRegisterKinds; - uint32_t reg_num = LLDB_INVALID_REGNUM; - FileSpec format_file_spec; - const RegisterInfo *reg_info = NULL; - RegisterContext *reg_ctx = NULL; - bool do_deref_pointer = false; - ValueObject::ExpressionPathScanEndReason reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString; - ValueObject::ExpressionPathEndResultType final_value_type = ValueObject::eExpressionPathEndResultTypePlain; - - // Each variable must set success to true below... - bool var_success = false; - switch (var_name_begin[0]) - { - case '*': - case 'v': - case 's': - { - if (!valobj) - break; - - if (log) - log->Printf("[Debugger::FormatPrompt] initial string: %s",var_name_begin); - - // check for *var and *svar - if (*var_name_begin == '*') - { - do_deref_pointer = true; - var_name_begin++; - if (log) - log->Printf("[Debugger::FormatPrompt] found a deref, new string is: %s",var_name_begin); - } - - if (*var_name_begin == 's') - { - if (!valobj->IsSynthetic()) - valobj = valobj->GetSyntheticValue().get(); - if (!valobj) - break; - var_name_begin++; - if (log) - log->Printf("[Debugger::FormatPrompt] found a synthetic, new string is: %s",var_name_begin); - } - - // should be a 'v' by now - if (*var_name_begin != 'v') - break; - - if (log) - log->Printf("[Debugger::FormatPrompt] string I am working with: %s",var_name_begin); - - ValueObject::ExpressionPathAftermath what_next = (do_deref_pointer ? - ValueObject::eExpressionPathAftermathDereference : ValueObject::eExpressionPathAftermathNothing); - ValueObject::GetValueForExpressionPathOptions options; - options.DontCheckDotVsArrowSyntax().DoAllowBitfieldSyntax().DoAllowFragileIVar().DoAllowSyntheticChildren(); - ValueObject::ValueObjectRepresentationStyle val_obj_display = ValueObject::eValueObjectRepresentationStyleSummary; - ValueObject* target = NULL; - Format custom_format = eFormatInvalid; - const char* var_name_final = NULL; - const char* var_name_final_if_array_range = NULL; - const char* close_bracket_position = NULL; - int64_t index_lower = -1; - int64_t index_higher = -1; - bool is_array_range = false; - const char* first_unparsed; - bool was_plain_var = false; - bool was_var_format = false; - bool was_var_indexed = false; - - if (!valobj) break; - // simplest case ${var}, just print valobj's value - if (IsToken (var_name_begin, "var}")) - { - was_plain_var = true; - target = valobj; - val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; - } - else if (IsToken (var_name_begin, "var.script:")) - { - var_name_begin += ::strlen("var.script:"); - std::string script_name(var_name_begin,var_name_end); - ScriptInterpreter* script_interpreter = valobj->GetTargetSP()->GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (RunScriptFormatKeyword (s, script_interpreter, valobj, script_name)) - var_success = true; - break; - } - else if (IsToken (var_name_begin,"var%")) - { - was_var_format = true; - // this is a variable with some custom format applied to it - const char* percent_position; - target = valobj; - val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; - ScanFormatDescriptor (var_name_begin, - var_name_end, - &var_name_final, - &percent_position, - &custom_format, - &val_obj_display); - } - // this is ${var.something} or multiple .something nested - else if (IsToken (var_name_begin, "var")) - { - if (IsToken (var_name_begin, "var[")) - was_var_indexed = true; - const char* percent_position; - ScanFormatDescriptor (var_name_begin, - var_name_end, - &var_name_final, - &percent_position, - &custom_format, - &val_obj_display); - - const char* open_bracket_position; - const char* separator_position; - ScanBracketedRange (var_name_begin, - var_name_end, - var_name_final, - &open_bracket_position, - &separator_position, - &close_bracket_position, - &var_name_final_if_array_range, - &index_lower, - &index_higher); - - Error error; - - std::string expr_path(var_name_final-var_name_begin-1,0); - memcpy(&expr_path[0], var_name_begin+3,var_name_final-var_name_begin-3); - - if (log) - log->Printf("[Debugger::FormatPrompt] symbol to expand: %s",expr_path.c_str()); - - target = valobj->GetValueForExpressionPath(expr_path.c_str(), - &first_unparsed, - &reason_to_stop, - &final_value_type, - options, - &what_next).get(); - - if (!target) - { - if (log) - log->Printf("[Debugger::FormatPrompt] ERROR: unparsed portion = %s, why stopping = %d," - " final_value_type %d", - first_unparsed, reason_to_stop, final_value_type); - break; - } - else - { - if (log) - log->Printf("[Debugger::FormatPrompt] ALL RIGHT: unparsed portion = %s, why stopping = %d," - " final_value_type %d", - first_unparsed, reason_to_stop, final_value_type); - target = target->GetQualifiedRepresentationIfAvailable(target->GetDynamicValueType(), true).get(); - } - } - else - break; - - is_array_range = (final_value_type == ValueObject::eExpressionPathEndResultTypeBoundedRange || - final_value_type == ValueObject::eExpressionPathEndResultTypeUnboundedRange); - - do_deref_pointer = (what_next == ValueObject::eExpressionPathAftermathDereference); - - if (do_deref_pointer && !is_array_range) - { - // I have not deref-ed yet, let's do it - // this happens when we are not going through GetValueForVariableExpressionPath - // to get to the target ValueObject - Error error; - target = target->Dereference(error).get(); - if (error.Fail()) - { - if (log) - log->Printf("[Debugger::FormatPrompt] ERROR: %s\n", error.AsCString("unknown")); \ - break; - } - do_deref_pointer = false; - } - - if (!target) - { - if (log) - log->Printf("[Debugger::FormatPrompt] could not calculate target for prompt expression"); - break; - } - - // we do not want to use the summary for a bitfield of type T:n - // if we were originally dealing with just a T - that would get - // us into an endless recursion - if (target->IsBitfield() && was_var_indexed) - { - // TODO: check for a (T:n)-specific summary - we should still obey that - StreamString bitfield_name; - bitfield_name.Printf("%s:%d", target->GetTypeName().AsCString(), target->GetBitfieldBitSize()); - lldb::TypeNameSpecifierImplSP type_sp(new TypeNameSpecifierImpl(bitfield_name.GetData(),false)); - if (!DataVisualization::GetSummaryForType(type_sp)) - val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; - } - - // TODO use flags for these - const uint32_t type_info_flags = target->GetClangType().GetTypeInfo(NULL); - bool is_array = (type_info_flags & eTypeIsArray) != 0; - bool is_pointer = (type_info_flags & eTypeIsPointer) != 0; - bool is_aggregate = target->GetClangType().IsAggregateType(); - - if ((is_array || is_pointer) && (!is_array_range) && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue) // this should be wrong, but there are some exceptions - { - StreamString str_temp; - if (log) - log->Printf("[Debugger::FormatPrompt] I am into array || pointer && !range"); - - if (target->HasSpecialPrintableRepresentation(val_obj_display, custom_format)) - { - // try to use the special cases - var_success = target->DumpPrintableRepresentation(str_temp, - val_obj_display, - custom_format); - if (log) - log->Printf("[Debugger::FormatPrompt] special cases did%s match", var_success ? "" : "n't"); - - // should not happen - if (var_success) - s << str_temp.GetData(); - var_success = true; - break; - } - else - { - if (was_plain_var) // if ${var} - { - s << target->GetTypeName() << " @ " << target->GetLocationAsCString(); - } - else if (is_pointer) // if pointer, value is the address stored - { - target->DumpPrintableRepresentation (s, - val_obj_display, - custom_format, - ValueObject::ePrintableRepresentationSpecialCasesDisable); - } - var_success = true; - break; - } - } - - // if directly trying to print ${var}, and this is an aggregate, display a nice - // type @ location message - if (is_aggregate && was_plain_var) - { - s << target->GetTypeName() << " @ " << target->GetLocationAsCString(); - var_success = true; - break; - } - - // if directly trying to print ${var%V}, and this is an aggregate, do not let the user do it - if (is_aggregate && ((was_var_format && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue))) - { - s << "<invalid use of aggregate type>"; - var_success = true; - break; - } - - if (!is_array_range) - { - if (log) - log->Printf("[Debugger::FormatPrompt] dumping ordinary printable output"); - var_success = target->DumpPrintableRepresentation(s,val_obj_display, custom_format); - } - else - { - if (log) - log->Printf("[Debugger::FormatPrompt] checking if I can handle as array"); - if (!is_array && !is_pointer) - break; - if (log) - log->Printf("[Debugger::FormatPrompt] handle as array"); - const char* special_directions = NULL; - StreamString special_directions_writer; - if (close_bracket_position && (var_name_end-close_bracket_position > 1)) - { - ConstString additional_data; - additional_data.SetCStringWithLength(close_bracket_position+1, var_name_end-close_bracket_position-1); - special_directions_writer.Printf("${%svar%s}", - do_deref_pointer ? "*" : "", - additional_data.GetCString()); - special_directions = special_directions_writer.GetData(); - } - - // let us display items index_lower thru index_higher of this array - s.PutChar('['); - var_success = true; - - if (index_higher < 0) - index_higher = valobj->GetNumChildren() - 1; - - uint32_t max_num_children = target->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay(); - - for (;index_lower<=index_higher;index_lower++) - { - ValueObject* item = ExpandIndexedExpression (target, - index_lower, - exe_ctx->GetFramePtr(), - false).get(); - - if (!item) - { - if (log) - log->Printf("[Debugger::FormatPrompt] ERROR in getting child item at index %" PRId64, index_lower); - } - else - { - if (log) - log->Printf("[Debugger::FormatPrompt] special_directions for child item: %s",special_directions); - } - - if (!special_directions) - var_success &= item->DumpPrintableRepresentation(s,val_obj_display, custom_format); - else - var_success &= FormatPromptRecurse(special_directions, sc, exe_ctx, addr, s, NULL, item, function_changed, initial_function); - - if (--max_num_children == 0) - { - s.PutCString(", ..."); - break; - } - - if (index_lower < index_higher) - s.PutChar(','); - } - s.PutChar(']'); - } - } - break; - case 'a': - if (IsToken (var_name_begin, "addr-file-or-load}")) - { - print_file_addr_or_load_addr = true; - } - if (IsToken (var_name_begin, "addr}") - || IsToken (var_name_begin, "addr-file-or-load}")) - { - if (addr && addr->IsValid()) - { - var_success = true; - format_addr = *addr; - } - } - break; - - case 'p': - if (IsToken (var_name_begin, "process.")) - { - if (exe_ctx) - { - Process *process = exe_ctx->GetProcessPtr(); - if (process) - { - var_name_begin += ::strlen ("process."); - if (IsTokenWithFormat (var_name_begin, "id", token_format, "%" PRIu64, exe_ctx, sc)) - { - s.Printf(token_format.c_str(), process->GetID()); - var_success = true; - } - else if ((IsToken (var_name_begin, "name}")) || - (IsToken (var_name_begin, "file.basename}")) || - (IsToken (var_name_begin, "file.fullpath}"))) - { - Module *exe_module = process->GetTarget().GetExecutableModulePointer(); - if (exe_module) - { - if (var_name_begin[0] == 'n' || var_name_begin[5] == 'f') - { - format_file_spec.GetFilename() = exe_module->GetFileSpec().GetFilename(); - var_success = (bool)format_file_spec; - } - else - { - format_file_spec = exe_module->GetFileSpec(); - var_success = (bool)format_file_spec; - } - } - } - else if (IsToken (var_name_begin, "script:")) - { - var_name_begin += ::strlen("script:"); - std::string script_name(var_name_begin,var_name_end); - ScriptInterpreter* script_interpreter = process->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (RunScriptFormatKeyword (s, script_interpreter, process, script_name)) - var_success = true; - } - } - } - } - break; - - case 't': - if (IsToken (var_name_begin, "thread.")) - { - if (exe_ctx) - { - Thread *thread = exe_ctx->GetThreadPtr(); - if (thread) - { - var_name_begin += ::strlen ("thread."); - if (IsTokenWithFormat (var_name_begin, "id", token_format, "0x%4.4" PRIx64, exe_ctx, sc)) - { - s.Printf(token_format.c_str(), thread->GetID()); - var_success = true; - } - else if (IsTokenWithFormat (var_name_begin, "protocol_id", token_format, "0x%4.4" PRIx64, exe_ctx, sc)) - { - s.Printf(token_format.c_str(), thread->GetProtocolID()); - var_success = true; - } - else if (IsTokenWithFormat (var_name_begin, "index", token_format, "%" PRIu64, exe_ctx, sc)) - { - s.Printf(token_format.c_str(), (uint64_t)thread->GetIndexID()); - var_success = true; - } - else if (IsToken (var_name_begin, "name}")) - { - cstr = thread->GetName(); - var_success = cstr && cstr[0]; - if (var_success) - s.PutCString(cstr); - } - else if (IsToken (var_name_begin, "queue}")) - { - cstr = thread->GetQueueName(); - var_success = cstr && cstr[0]; - if (var_success) - s.PutCString(cstr); - } - else if (IsToken (var_name_begin, "stop-reason}")) - { - StopInfoSP stop_info_sp = thread->GetStopInfo (); - if (stop_info_sp && stop_info_sp->IsValid()) - { - cstr = stop_info_sp->GetDescription(); - if (cstr && cstr[0]) - { - s.PutCString(cstr); - var_success = true; - } - } - } - else if (IsToken (var_name_begin, "return-value}")) - { - StopInfoSP stop_info_sp = thread->GetStopInfo (); - if (stop_info_sp && stop_info_sp->IsValid()) - { - ValueObjectSP return_valobj_sp = StopInfo::GetReturnValueObject (stop_info_sp); - if (return_valobj_sp) - { - return_valobj_sp->Dump(s); - var_success = true; - } - } - } - else if (IsToken (var_name_begin, "completed-expression}")) - { - StopInfoSP stop_info_sp = thread->GetStopInfo (); - if (stop_info_sp && stop_info_sp->IsValid()) - { - ClangExpressionVariableSP expression_var_sp = StopInfo::GetExpressionVariable (stop_info_sp); - if (expression_var_sp && expression_var_sp->GetValueObject()) - { - expression_var_sp->GetValueObject()->Dump(s); - var_success = true; - } - } - } - else if (IsToken (var_name_begin, "script:")) - { - var_name_begin += ::strlen("script:"); - std::string script_name(var_name_begin,var_name_end); - ScriptInterpreter* script_interpreter = thread->GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (RunScriptFormatKeyword (s, script_interpreter, thread, script_name)) - var_success = true; - } - else if (IsToken (var_name_begin, "info.")) - { - var_name_begin += ::strlen("info."); - StructuredData::ObjectSP object_sp = thread->GetExtendedInfo(); - if (object_sp && object_sp->GetType() == StructuredData::Type::eTypeDictionary) - { - var_success = FormatThreadExtendedInfoRecurse (var_name_begin, object_sp, sc, exe_ctx, s); - } - } - } - } - } - else if (IsToken (var_name_begin, "target.")) - { - // TODO: hookup properties -// if (!target_properties_sp) -// { -// Target *target = Target::GetTargetFromContexts (exe_ctx, sc); -// if (target) -// target_properties_sp = target->GetProperties(); -// } -// -// if (target_properties_sp) -// { -// var_name_begin += ::strlen ("target."); -// const char *end_property = strchr(var_name_begin, '}'); -// if (end_property) -// { -// ConstString property_name(var_name_begin, end_property - var_name_begin); -// std::string property_value (target_properties_sp->GetPropertyValue(property_name)); -// if (!property_value.empty()) -// { -// s.PutCString (property_value.c_str()); -// var_success = true; -// } -// } -// } - Target *target = Target::GetTargetFromContexts (exe_ctx, sc); - if (target) - { - var_name_begin += ::strlen ("target."); - if (IsToken (var_name_begin, "arch}")) - { - ArchSpec arch (target->GetArchitecture ()); - if (arch.IsValid()) - { - s.PutCString (arch.GetArchitectureName()); - var_success = true; - } - } - else if (IsToken (var_name_begin, "script:")) - { - var_name_begin += ::strlen("script:"); - std::string script_name(var_name_begin,var_name_end); - ScriptInterpreter* script_interpreter = target->GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (RunScriptFormatKeyword (s, script_interpreter, target, script_name)) - var_success = true; - } - } - } - break; - - case 'm': - if (IsToken (var_name_begin, "module.")) - { - if (sc && sc->module_sp.get()) - { - Module *module = sc->module_sp.get(); - var_name_begin += ::strlen ("module."); - - if (IsToken (var_name_begin, "file.")) - { - if (module->GetFileSpec()) - { - var_name_begin += ::strlen ("file."); - - if (IsToken (var_name_begin, "basename}")) - { - format_file_spec.GetFilename() = module->GetFileSpec().GetFilename(); - var_success = (bool)format_file_spec; - } - else if (IsToken (var_name_begin, "fullpath}")) - { - format_file_spec = module->GetFileSpec(); - var_success = (bool)format_file_spec; - } - } - } - } - } - break; - - - case 'f': - if (IsToken (var_name_begin, "file.")) - { - if (sc && sc->comp_unit != NULL) - { - var_name_begin += ::strlen ("file."); - - if (IsToken (var_name_begin, "basename}")) - { - format_file_spec.GetFilename() = sc->comp_unit->GetFilename(); - var_success = (bool)format_file_spec; - } - else if (IsToken (var_name_begin, "fullpath}")) - { - format_file_spec = *sc->comp_unit; - var_success = (bool)format_file_spec; - } - } - } - else if (IsToken (var_name_begin, "frame.")) - { - if (exe_ctx) - { - StackFrame *frame = exe_ctx->GetFramePtr(); - if (frame) - { - var_name_begin += ::strlen ("frame."); - if (IsToken (var_name_begin, "index}")) - { - s.Printf("%u", frame->GetFrameIndex()); - var_success = true; - } - else if (IsToken (var_name_begin, "pc}")) - { - reg_kind = eRegisterKindGeneric; - reg_num = LLDB_REGNUM_GENERIC_PC; - var_success = true; - } - else if (IsToken (var_name_begin, "sp}")) - { - reg_kind = eRegisterKindGeneric; - reg_num = LLDB_REGNUM_GENERIC_SP; - var_success = true; - } - else if (IsToken (var_name_begin, "fp}")) - { - reg_kind = eRegisterKindGeneric; - reg_num = LLDB_REGNUM_GENERIC_FP; - var_success = true; - } - else if (IsToken (var_name_begin, "flags}")) - { - reg_kind = eRegisterKindGeneric; - reg_num = LLDB_REGNUM_GENERIC_FLAGS; - var_success = true; - } - else if (IsToken (var_name_begin, "reg.")) - { - reg_ctx = frame->GetRegisterContext().get(); - if (reg_ctx) - { - var_name_begin += ::strlen ("reg."); - if (var_name_begin < var_name_end) - { - std::string reg_name (var_name_begin, var_name_end); - reg_info = reg_ctx->GetRegisterInfoByName (reg_name.c_str()); - if (reg_info) - var_success = true; - } - } - } - else if (IsToken (var_name_begin, "script:")) - { - var_name_begin += ::strlen("script:"); - std::string script_name(var_name_begin,var_name_end); - ScriptInterpreter* script_interpreter = frame->GetThread()->GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (RunScriptFormatKeyword (s, script_interpreter, frame, script_name)) - var_success = true; - } - } - } - } - else if (IsToken (var_name_begin, "function.")) - { - if (sc && (sc->function != NULL || sc->symbol != NULL)) - { - var_name_begin += ::strlen ("function."); - if (IsToken (var_name_begin, "id}")) - { - if (sc->function) - s.Printf("function{0x%8.8" PRIx64 "}", sc->function->GetID()); - else - s.Printf("symbol[%u]", sc->symbol->GetID()); - - var_success = true; - } - if (IsToken (var_name_begin, "changed}") && function_changed) - { - var_success = true; - } - if (IsToken (var_name_begin, "initial-function}") && initial_function) - { - var_success = true; - } - else if (IsToken (var_name_begin, "name}")) - { - if (sc->function) - cstr = sc->function->GetName().AsCString (NULL); - else if (sc->symbol) - cstr = sc->symbol->GetName().AsCString (NULL); - if (cstr) - { - s.PutCString(cstr); - - if (sc->block) - { - Block *inline_block = sc->block->GetContainingInlinedBlock (); - if (inline_block) - { - const InlineFunctionInfo *inline_info = sc->block->GetInlinedFunctionInfo(); - if (inline_info) - { - s.PutCString(" [inlined] "); - inline_info->GetName().Dump(&s); - } - } - } - var_success = true; - } - } - else if (IsToken (var_name_begin, "name-without-args}")) - { - ConstString name; - if (sc->function) - name = sc->function->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments); - else if (sc->symbol) - name = sc->symbol->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments); - if (name) - { - s.PutCString(name.GetCString()); - var_success = true; - } - } - else if (IsToken (var_name_begin, "name-with-args}")) - { - // Print the function name with arguments in it - - if (sc->function) - { - var_success = true; - ExecutionContextScope *exe_scope = exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL; - cstr = sc->function->GetName().AsCString (NULL); - if (cstr) - { - const InlineFunctionInfo *inline_info = NULL; - VariableListSP variable_list_sp; - bool get_function_vars = true; - if (sc->block) - { - Block *inline_block = sc->block->GetContainingInlinedBlock (); - - if (inline_block) - { - get_function_vars = false; - inline_info = sc->block->GetInlinedFunctionInfo(); - if (inline_info) - variable_list_sp = inline_block->GetBlockVariableList (true); - } - } - - if (get_function_vars) - { - variable_list_sp = sc->function->GetBlock(true).GetBlockVariableList (true); - } - - if (inline_info) - { - s.PutCString (cstr); - s.PutCString (" [inlined] "); - cstr = inline_info->GetName().GetCString(); - } - - VariableList args; - if (variable_list_sp) - variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument, args); - if (args.GetSize() > 0) - { - const char *open_paren = strchr (cstr, '('); - const char *close_paren = nullptr; - const char *generic = strchr(cstr, '<'); - // if before the arguments list begins there is a template sign - // then scan to the end of the generic args before you try to find - // the arguments list - if (generic && open_paren && generic < open_paren) - { - int generic_depth = 1; - ++generic; - for (; - *generic && generic_depth > 0; - generic++) - { - if (*generic == '<') - generic_depth++; - if (*generic == '>') - generic_depth--; - } - if (*generic) - open_paren = strchr(generic, '('); - else - open_paren = nullptr; - } - if (open_paren) - { - if (IsToken (open_paren, "(anonymous namespace)")) - { - open_paren = strchr (open_paren + strlen("(anonymous namespace)"), '('); - if (open_paren) - close_paren = strchr (open_paren, ')'); - } - else - close_paren = strchr (open_paren, ')'); - } - - if (open_paren) - s.Write(cstr, open_paren - cstr + 1); - else - { - s.PutCString (cstr); - s.PutChar ('('); - } - const size_t num_args = args.GetSize(); - for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx) - { - std::string buffer; - - VariableSP var_sp (args.GetVariableAtIndex (arg_idx)); - ValueObjectSP var_value_sp (ValueObjectVariable::Create (exe_scope, var_sp)); - const char *var_representation = nullptr; - const char *var_name = var_value_sp->GetName().GetCString(); - if (var_value_sp->GetClangType().IsAggregateType() && - DataVisualization::ShouldPrintAsOneLiner(*var_value_sp.get())) - { - static StringSummaryFormat format(TypeSummaryImpl::Flags() - .SetHideItemNames(false) - .SetShowMembersOneLiner(true), - ""); - format.FormatObject(var_value_sp.get(), buffer, TypeSummaryOptions()); - var_representation = buffer.c_str(); - } - else - var_representation = var_value_sp->GetValueAsCString(); - if (arg_idx > 0) - s.PutCString (", "); - if (var_value_sp->GetError().Success()) - { - if (var_representation) - s.Printf ("%s=%s", var_name, var_representation); - else - s.Printf ("%s=%s at %s", var_name, var_value_sp->GetTypeName().GetCString(), var_value_sp->GetLocationAsCString()); - } - else - s.Printf ("%s=<unavailable>", var_name); - } - - if (close_paren) - s.PutCString (close_paren); - else - s.PutChar(')'); - - } - else - { - s.PutCString(cstr); - } - } - } - else if (sc->symbol) - { - cstr = sc->symbol->GetName().AsCString (NULL); - if (cstr) - { - s.PutCString(cstr); - var_success = true; - } - } - } - else if (IsToken (var_name_begin, "addr-offset}") - || IsToken (var_name_begin, "concrete-only-addr-offset-no-padding}")) - { - if (IsToken (var_name_begin, "concrete-only-addr-offset-no-padding}")) - { - addr_offset_print_with_no_padding = true; - addr_offset_concrete_func_only = true; - } - var_success = addr != NULL; - if (var_success) - { - format_addr = *addr; - calculate_format_addr_function_offset = true; - } - } - else if (IsToken (var_name_begin, "line-offset}")) - { - var_success = sc->line_entry.range.GetBaseAddress().IsValid(); - if (var_success) - { - format_addr = sc->line_entry.range.GetBaseAddress(); - calculate_format_addr_function_offset = true; - } - } - else if (IsToken (var_name_begin, "pc-offset}")) - { - StackFrame *frame = exe_ctx->GetFramePtr(); - var_success = frame != NULL; - if (var_success) - { - format_addr = frame->GetFrameCodeAddress(); - calculate_format_addr_function_offset = true; - } - } - } - } - break; - - case 'l': - if (IsToken (var_name_begin, "line.")) - { - if (sc && sc->line_entry.IsValid()) - { - var_name_begin += ::strlen ("line."); - if (IsToken (var_name_begin, "file.")) - { - var_name_begin += ::strlen ("file."); - - if (IsToken (var_name_begin, "basename}")) - { - format_file_spec.GetFilename() = sc->line_entry.file.GetFilename(); - var_success = (bool)format_file_spec; - } - else if (IsToken (var_name_begin, "fullpath}")) - { - format_file_spec = sc->line_entry.file; - var_success = (bool)format_file_spec; - } - } - else if (IsTokenWithFormat (var_name_begin, "number", token_format, "%" PRIu64, exe_ctx, sc)) - { - var_success = true; - s.Printf(token_format.c_str(), (uint64_t)sc->line_entry.line); - } - else if ((IsToken (var_name_begin, "start-addr}")) || - (IsToken (var_name_begin, "end-addr}"))) - { - var_success = sc && sc->line_entry.range.GetBaseAddress().IsValid(); - if (var_success) - { - format_addr = sc->line_entry.range.GetBaseAddress(); - if (var_name_begin[0] == 'e') - format_addr.Slide (sc->line_entry.range.GetByteSize()); - } - } - } - } - break; - case 'c': - if (IsToken (var_name_begin, "current-pc-arrow")) - { - if (addr && exe_ctx && exe_ctx->GetFramePtr()) - { - RegisterContextSP reg_ctx = exe_ctx->GetFramePtr()->GetRegisterContextSP(); - if (reg_ctx.get()) - { - addr_t pc_loadaddr = reg_ctx->GetPC(); - if (pc_loadaddr != LLDB_INVALID_ADDRESS) - { - Address pc; - pc.SetLoadAddress (pc_loadaddr, exe_ctx->GetTargetPtr()); - if (pc == *addr) - { - s.Printf ("-> "); - var_success = true; - } - } - } - if (var_success == false) - { - s.Printf(" "); - var_success = true; - } - } - var_success = true; - } - break; - } - - if (var_success) - { - // If format addr is valid, then we need to print an address - if (reg_num != LLDB_INVALID_REGNUM) - { - StackFrame *frame = exe_ctx->GetFramePtr(); - // We have a register value to display... - if (reg_num == LLDB_REGNUM_GENERIC_PC && reg_kind == eRegisterKindGeneric) - { - format_addr = frame->GetFrameCodeAddress(); - } - else - { - if (reg_ctx == NULL) - reg_ctx = frame->GetRegisterContext().get(); - - if (reg_ctx) - { - if (reg_kind != kNumRegisterKinds) - reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num); - reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_num); - var_success = reg_info != NULL; - } - } - } - - if (reg_info != NULL) - { - RegisterValue reg_value; - var_success = reg_ctx->ReadRegister (reg_info, reg_value); - if (var_success) - { - reg_value.Dump(&s, reg_info, false, false, eFormatDefault); - } - } - - if (format_file_spec) - { - s << format_file_spec; - } - - // If format addr is valid, then we need to print an address - if (format_addr.IsValid()) - { - var_success = false; - - if (calculate_format_addr_function_offset) - { - Address func_addr; - - if (sc) - { - if (sc->function) - { - func_addr = sc->function->GetAddressRange().GetBaseAddress(); - if (sc->block && addr_offset_concrete_func_only == false) - { - // Check to make sure we aren't in an inline - // function. If we are, use the inline block - // range that contains "format_addr" since - // blocks can be discontiguous. - Block *inline_block = sc->block->GetContainingInlinedBlock (); - AddressRange inline_range; - if (inline_block && inline_block->GetRangeContainingAddress (format_addr, inline_range)) - func_addr = inline_range.GetBaseAddress(); - } - } - else if (sc->symbol && sc->symbol->ValueIsAddress()) - func_addr = sc->symbol->GetAddress(); - } - - if (func_addr.IsValid()) - { - const char *addr_offset_padding = " "; - if (addr_offset_print_with_no_padding) - { - addr_offset_padding = ""; - } - if (func_addr.GetSection() == format_addr.GetSection()) - { - addr_t func_file_addr = func_addr.GetFileAddress(); - addr_t addr_file_addr = format_addr.GetFileAddress(); - if (addr_file_addr > func_file_addr) - s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, addr_file_addr - func_file_addr); - else if (addr_file_addr < func_file_addr) - s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_file_addr - addr_file_addr); - var_success = true; - } - else - { - Target *target = Target::GetTargetFromContexts (exe_ctx, sc); - if (target) - { - addr_t func_load_addr = func_addr.GetLoadAddress (target); - addr_t addr_load_addr = format_addr.GetLoadAddress (target); - if (addr_load_addr > func_load_addr) - s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, addr_load_addr - func_load_addr); - else if (addr_load_addr < func_load_addr) - s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_load_addr - addr_load_addr); - var_success = true; - } - } - } - } - else - { - Target *target = Target::GetTargetFromContexts (exe_ctx, sc); - addr_t vaddr = LLDB_INVALID_ADDRESS; - if (exe_ctx && !target->GetSectionLoadList().IsEmpty()) - vaddr = format_addr.GetLoadAddress (target); - if (vaddr == LLDB_INVALID_ADDRESS) - vaddr = format_addr.GetFileAddress (); - - if (vaddr != LLDB_INVALID_ADDRESS) - { - int addr_width = 0; - if (exe_ctx && target) - { - addr_width = target->GetArchitecture().GetAddressByteSize() * 2; - } - if (addr_width == 0) - addr_width = 16; - if (print_file_addr_or_load_addr) - { - format_addr.Dump (&s, exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress, 0); - } - else - { - s.Printf("0x%*.*" PRIx64, addr_width, addr_width, vaddr); - } - var_success = true; - } - } - } - } - - if (var_success == false) - success = false; - } - p = var_name_end; - } - else - break; - } - else - { - // We got a dollar sign with no '{' after it, it must just be a dollar sign - s.PutChar(*p); - } - } - else if (*p == '\\') - { - ++p; // skip the slash - switch (*p) - { - case 'a': s.PutChar ('\a'); break; - case 'b': s.PutChar ('\b'); break; - case 'f': s.PutChar ('\f'); break; - case 'n': s.PutChar ('\n'); break; - case 'r': s.PutChar ('\r'); break; - case 't': s.PutChar ('\t'); break; - case 'v': s.PutChar ('\v'); break; - case '\'': s.PutChar ('\''); break; - case '\\': s.PutChar ('\\'); break; - case '0': - // 1 to 3 octal chars - { - // Make a string that can hold onto the initial zero char, - // up to 3 octal digits, and a terminating NULL. - char oct_str[5] = { 0, 0, 0, 0, 0 }; - - int i; - for (i=0; (p[i] >= '0' && p[i] <= '7') && i<4; ++i) - oct_str[i] = p[i]; - - // We don't want to consume the last octal character since - // the main for loop will do this for us, so we advance p by - // one less than i (even if i is zero) - p += i - 1; - unsigned long octal_value = ::strtoul (oct_str, NULL, 8); - if (octal_value <= UINT8_MAX) - { - s.PutChar((char)octal_value); - } - } - break; - - case 'x': - // hex number in the format - if (isxdigit(p[1])) - { - ++p; // Skip the 'x' - - // Make a string that can hold onto two hex chars plus a - // NULL terminator - char hex_str[3] = { 0,0,0 }; - hex_str[0] = *p; - if (isxdigit(p[1])) - { - ++p; // Skip the first of the two hex chars - hex_str[1] = *p; - } - - unsigned long hex_value = strtoul (hex_str, NULL, 16); - if (hex_value <= UINT8_MAX) - s.PutChar ((char)hex_value); - } - else - { - s.PutChar('x'); - } - break; - - default: - // Just desensitize any other character by just printing what - // came after the '\' - s << *p; - break; - - } - - } - } - if (end) - *end = p; - return success; -} - bool -Debugger::FormatPrompt -( - const char *format, - const SymbolContext *sc, - const ExecutionContext *exe_ctx, - const Address *addr, - Stream &s, - ValueObject* valobj -) -{ - bool use_color = exe_ctx ? exe_ctx->GetTargetRef().GetDebugger().GetUseColor() : true; - std::string format_str = lldb_utility::ansi::FormatAnsiTerminalCodes (format, use_color); - if (format_str.length()) - format = format_str.c_str(); - return FormatPromptRecurse (format, sc, exe_ctx, addr, s, NULL, valobj, false, false); -} - -bool -Debugger::FormatDisassemblerAddress (const char *format, +Debugger::FormatDisassemblerAddress (const FormatEntity::Entry *format, const SymbolContext *sc, const SymbolContext *prev_sc, const ExecutionContext *exe_ctx, const Address *addr, Stream &s) { - if (format == NULL && exe_ctx != NULL && exe_ctx->HasTargetScope()) + FormatEntity::Entry format_entry; + + if (format == NULL) { - format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat(); + if (exe_ctx != NULL && exe_ctx->HasTargetScope()) + format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat(); + if (format == NULL) + { + FormatEntity::Parse("${addr}: ", format_entry); + format = &format_entry; + } } bool function_changed = false; bool initial_function = false; @@ -2942,7 +1276,7 @@ Debugger::FormatDisassemblerAddress (const char *format, { initial_function = true; } - return FormatPromptRecurse (format, sc, exe_ctx, addr, s, NULL, NULL, function_changed, initial_function); + return FormatEntity::Format(*format, s, sc, exe_ctx, addr, NULL, function_changed, initial_function); } |