diff options
author | emaste <emaste@FreeBSD.org> | 2013-08-23 18:06:42 +0000 |
---|---|---|
committer | emaste <emaste@FreeBSD.org> | 2013-08-23 18:06:42 +0000 |
commit | 424d4dadd208e2a1e9a43c3d55f47f03ba0c4509 (patch) | |
tree | 05d762b98a499804ce690e6ce04033f1ddf4dee6 /contrib/llvm/tools/lldb/source/Symbol/Variable.cpp | |
parent | cde487f27a84e02a560384f75178fddca68740f6 (diff) | |
parent | dcd15f81789e389c1cb27d264fcdddfd0a6002bd (diff) | |
download | FreeBSD-src-424d4dadd208e2a1e9a43c3d55f47f03ba0c4509.zip FreeBSD-src-424d4dadd208e2a1e9a43c3d55f47f03ba0c4509.tar.gz |
Merge lldb r188801 to contrib/llvm/tools/lldb/
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Symbol/Variable.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Symbol/Variable.cpp | 894 |
1 files changed, 894 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Symbol/Variable.cpp b/contrib/llvm/tools/lldb/source/Symbol/Variable.cpp new file mode 100644 index 0000000..36439b5 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Symbol/Variable.cpp @@ -0,0 +1,894 @@ +//===-- Variable.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/Variable.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectVariable.h" +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Variable constructor +//---------------------------------------------------------------------- +Variable::Variable +( + lldb::user_id_t uid, + const char *name, + const char *mangled, // The mangled variable name for variables in namespaces + const lldb::SymbolFileTypeSP &symfile_type_sp, + ValueType scope, + SymbolContextScope *context, + Declaration* decl_ptr, + const DWARFExpression& location, + bool external, + bool artificial +) : + UserID(uid), + m_name(name), + m_mangled (ConstString(mangled), true), + m_symfile_type_sp(symfile_type_sp), + m_scope(scope), + m_owner_scope(context), + m_declaration(decl_ptr), + m_location(location), + m_external(external), + m_artificial(artificial) +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +Variable::~Variable() +{ +} + + +const ConstString& +Variable::GetName() const +{ + if (m_mangled) + return m_mangled.GetName(); + return m_name; +} + +bool +Variable::NameMatches (const RegularExpression& regex) const +{ + if (regex.Execute (m_name.AsCString())) + return true; + return m_mangled.NameMatches (regex); +} + +Type * +Variable::GetType() +{ + if (m_symfile_type_sp) + return m_symfile_type_sp->GetType(); + return NULL; +} + +void +Variable::Dump(Stream *s, bool show_context) const +{ + s->Printf("%p: ", this); + s->Indent(); + *s << "Variable" << (const UserID&)*this; + + if (m_name) + *s << ", name = \"" << m_name << "\""; + + if (m_symfile_type_sp) + { + Type *type = m_symfile_type_sp->GetType(); + if (type) + { + *s << ", type = {" << type->GetID() << "} " << (void*)type << " ("; + type->DumpTypeName(s); + s->PutChar(')'); + } + } + + if (m_scope != eValueTypeInvalid) + { + s->PutCString(", scope = "); + switch (m_scope) + { + case eValueTypeVariableGlobal: s->PutCString(m_external ? "global" : "static"); break; + case eValueTypeVariableArgument: s->PutCString("parameter"); break; + case eValueTypeVariableLocal: s->PutCString("local"); break; + default: *s << "??? (" << m_scope << ')'; + } + } + + if (show_context && m_owner_scope != NULL) + { + s->PutCString(", context = ( "); + m_owner_scope->DumpSymbolContext(s); + s->PutCString(" )"); + } + + bool show_fullpaths = false; + m_declaration.Dump(s, show_fullpaths); + + if (m_location.IsValid()) + { + s->PutCString(", location = "); + lldb::addr_t loclist_base_addr = LLDB_INVALID_ADDRESS; + if (m_location.IsLocationList()) + { + SymbolContext variable_sc; + m_owner_scope->CalculateSymbolContext(&variable_sc); + if (variable_sc.function) + loclist_base_addr = variable_sc.function->GetAddressRange().GetBaseAddress().GetFileAddress(); + } + ABI *abi = NULL; + if (m_owner_scope) + { + ModuleSP module_sp (m_owner_scope->CalculateSymbolContextModule()); + if (module_sp) + abi = ABI::FindPlugin (module_sp->GetArchitecture()).get(); + } + m_location.GetDescription(s, lldb::eDescriptionLevelBrief, loclist_base_addr, abi); + } + + if (m_external) + s->PutCString(", external"); + + if (m_artificial) + s->PutCString(", artificial"); + + s->EOL(); +} + +bool +Variable::DumpDeclaration (Stream *s, bool show_fullpaths, bool show_module) +{ + bool dumped_declaration_info = false; + if (m_owner_scope) + { + SymbolContext sc; + m_owner_scope->CalculateSymbolContext(&sc); + sc.block = NULL; + sc.line_entry.Clear(); + bool show_inlined_frames = false; + + dumped_declaration_info = sc.DumpStopContext (s, + NULL, + Address(), + show_fullpaths, + show_module, + show_inlined_frames); + + if (sc.function) + s->PutChar(':'); + } + if (m_declaration.DumpStopContext (s, false)) + dumped_declaration_info = true; + return dumped_declaration_info; +} + +size_t +Variable::MemorySize() const +{ + return sizeof(Variable); +} + + +void +Variable::CalculateSymbolContext (SymbolContext *sc) +{ + if (m_owner_scope) + m_owner_scope->CalculateSymbolContext(sc); + else + sc->Clear(false); +} + +bool +Variable::LocationIsValidForFrame (StackFrame *frame) +{ + // Is the variable is described by a single location? + if (!m_location.IsLocationList()) + { + // Yes it is, the location is valid. + return true; + } + + if (frame) + { + Function *function = frame->GetSymbolContext(eSymbolContextFunction).function; + if (function) + { + TargetSP target_sp (frame->CalculateTarget()); + + addr_t loclist_base_load_addr = function->GetAddressRange().GetBaseAddress().GetLoadAddress (target_sp.get()); + if (loclist_base_load_addr == LLDB_INVALID_ADDRESS) + return false; + // It is a location list. We just need to tell if the location + // list contains the current address when converted to a load + // address + return m_location.LocationListContainsAddress (loclist_base_load_addr, + frame->GetFrameCodeAddress().GetLoadAddress (target_sp.get())); + } + } + return false; +} + +bool +Variable::LocationIsValidForAddress (const Address &address) +{ + // Be sure to resolve the address to section offset prior to + // calling this function. + if (address.IsSectionOffset()) + { + SymbolContext sc; + CalculateSymbolContext(&sc); + if (sc.module_sp == address.GetModule()) + { + // Is the variable is described by a single location? + if (!m_location.IsLocationList()) + { + // Yes it is, the location is valid. + return true; + } + + if (sc.function) + { + addr_t loclist_base_file_addr = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress(); + if (loclist_base_file_addr == LLDB_INVALID_ADDRESS) + return false; + // It is a location list. We just need to tell if the location + // list contains the current address when converted to a load + // address + return m_location.LocationListContainsAddress (loclist_base_file_addr, + address.GetFileAddress()); + } + } + } + return false; +} + +bool +Variable::IsInScope (StackFrame *frame) +{ + switch (m_scope) + { + case eValueTypeRegister: + case eValueTypeRegisterSet: + return frame != NULL; + + case eValueTypeConstResult: + case eValueTypeVariableGlobal: + case eValueTypeVariableStatic: + return true; + + case eValueTypeVariableArgument: + case eValueTypeVariableLocal: + if (frame) + { + // We don't have a location list, we just need to see if the block + // that this variable was defined in is currently + Block *deepest_frame_block = frame->GetSymbolContext(eSymbolContextBlock).block; + if (deepest_frame_block) + { + SymbolContext variable_sc; + CalculateSymbolContext (&variable_sc); + // Check for static or global variable defined at the compile unit + // level that wasn't defined in a block + if (variable_sc.block == NULL) + return true; + + if (variable_sc.block == deepest_frame_block) + return true; + return variable_sc.block->Contains (deepest_frame_block); + } + } + break; + + default: + break; + } + return false; +} + +Error +Variable::GetValuesForVariableExpressionPath (const char *variable_expr_path, + ExecutionContextScope *scope, + GetVariableCallback callback, + void *baton, + VariableList &variable_list, + ValueObjectList &valobj_list) +{ + Error error; + if (variable_expr_path && callback) + { + switch (variable_expr_path[0]) + { + case '*': + { + error = Variable::GetValuesForVariableExpressionPath (variable_expr_path + 1, + scope, + callback, + baton, + variable_list, + valobj_list); + if (error.Success()) + { + for (uint32_t i=0; i<valobj_list.GetSize(); ) + { + Error tmp_error; + ValueObjectSP valobj_sp (valobj_list.GetValueObjectAtIndex(i)->Dereference(tmp_error)); + if (tmp_error.Fail()) + { + variable_list.RemoveVariableAtIndex (i); + valobj_list.RemoveValueObjectAtIndex (i); + } + else + { + valobj_list.SetValueObjectAtIndex (i, valobj_sp); + ++i; + } + } + } + else + { + error.SetErrorString ("unknown error"); + } + return error; + } + break; + + case '&': + { + error = Variable::GetValuesForVariableExpressionPath (variable_expr_path + 1, + scope, + callback, + baton, + variable_list, + valobj_list); + if (error.Success()) + { + for (uint32_t i=0; i<valobj_list.GetSize(); ) + { + Error tmp_error; + ValueObjectSP valobj_sp (valobj_list.GetValueObjectAtIndex(i)->AddressOf(tmp_error)); + if (tmp_error.Fail()) + { + variable_list.RemoveVariableAtIndex (i); + valobj_list.RemoveValueObjectAtIndex (i); + } + else + { + valobj_list.SetValueObjectAtIndex (i, valobj_sp); + ++i; + } + } + } + else + { + error.SetErrorString ("unknown error"); + } + return error; + } + break; + + default: + { + static RegularExpression g_regex ("^([A-Za-z_:][A-Za-z_0-9:]*)(.*)"); + RegularExpression::Match regex_match(1); + if (g_regex.Execute(variable_expr_path, ®ex_match)) + { + std::string variable_name; + if (regex_match.GetMatchAtIndex(variable_expr_path, 1, variable_name)) + { + variable_list.Clear(); + if (callback (baton, variable_name.c_str(), variable_list)) + { + uint32_t i=0; + while (i < variable_list.GetSize()) + { + VariableSP var_sp (variable_list.GetVariableAtIndex (i)); + ValueObjectSP valobj_sp; + if (var_sp) + { + ValueObjectSP variable_valobj_sp(ValueObjectVariable::Create (scope, var_sp)); + if (variable_valobj_sp) + { + const char *variable_sub_expr_path = variable_expr_path + variable_name.size(); + if (*variable_sub_expr_path) + { + const char* first_unparsed = NULL; + ValueObject::ExpressionPathScanEndReason reason_to_stop; + ValueObject::ExpressionPathEndResultType final_value_type; + ValueObject::GetValueForExpressionPathOptions options; + ValueObject::ExpressionPathAftermath final_task_on_target; + + valobj_sp = variable_valobj_sp->GetValueForExpressionPath (variable_sub_expr_path, + &first_unparsed, + &reason_to_stop, + &final_value_type, + options, + &final_task_on_target); + if (!valobj_sp) + { + error.SetErrorStringWithFormat ("invalid expression path '%s' for variable '%s'", + variable_sub_expr_path, + var_sp->GetName().GetCString()); + } + } + else + { + // Just the name of a variable with no extras + valobj_sp = variable_valobj_sp; + } + } + } + + if (!var_sp || !valobj_sp) + { + variable_list.RemoveVariableAtIndex (i); + } + else + { + valobj_list.Append(valobj_sp); + ++i; + } + } + + if (variable_list.GetSize() > 0) + { + error.Clear(); + return error; + } + } + } + } + error.SetErrorStringWithFormat ("unable to extract a variable name from '%s'", variable_expr_path); + } + break; + } + } + error.SetErrorString ("unknown error"); + return error; +} + +bool +Variable::DumpLocationForAddress (Stream *s, const Address &address) +{ + // Be sure to resolve the address to section offset prior to + // calling this function. + if (address.IsSectionOffset()) + { + SymbolContext sc; + CalculateSymbolContext(&sc); + if (sc.module_sp == address.GetModule()) + { + ABI *abi = NULL; + if (m_owner_scope) + { + ModuleSP module_sp (m_owner_scope->CalculateSymbolContextModule()); + if (module_sp) + abi = ABI::FindPlugin (module_sp->GetArchitecture()).get(); + } + + const addr_t file_addr = address.GetFileAddress(); + if (sc.function) + { + if (sc.function->GetAddressRange().ContainsFileAddress(address)) + { + addr_t loclist_base_file_addr = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress(); + if (loclist_base_file_addr == LLDB_INVALID_ADDRESS) + return false; + return m_location.DumpLocationForAddress (s, + eDescriptionLevelBrief, + loclist_base_file_addr, + file_addr, + abi); + } + } + return m_location.DumpLocationForAddress (s, + eDescriptionLevelBrief, + LLDB_INVALID_ADDRESS, + file_addr, + abi); + } + } + return false; +} + + +static void +PrivateAutoComplete (StackFrame *frame, + const std::string &partial_path, + const std::string &prefix_path, // Anything that has been resolved already will be in here + const ClangASTType& clang_type, + StringList &matches, + bool &word_complete); + +static void +PrivateAutoCompleteMembers (StackFrame *frame, + const std::string &partial_member_name, + const std::string &partial_path, + const std::string &prefix_path, // Anything that has been resolved already will be in here + const ClangASTType& clang_type, + StringList &matches, + bool &word_complete); + +static void +PrivateAutoCompleteMembers (StackFrame *frame, + const std::string &partial_member_name, + const std::string &partial_path, + const std::string &prefix_path, // Anything that has been resolved already will be in here + const ClangASTType& clang_type, + StringList &matches, + bool &word_complete) +{ + + // We are in a type parsing child members + const uint32_t num_bases = clang_type.GetNumDirectBaseClasses(); + + if (num_bases > 0) + { + for (uint32_t i = 0; i < num_bases; ++i) + { + ClangASTType base_class_type (clang_type.GetDirectBaseClassAtIndex (i, NULL)); + + PrivateAutoCompleteMembers (frame, + partial_member_name, + partial_path, + prefix_path, + base_class_type.GetCanonicalType(), + matches, + word_complete); + } + } + + const uint32_t num_vbases = clang_type.GetNumVirtualBaseClasses(); + + if (num_vbases > 0) + { + for (uint32_t i = 0; i < num_vbases; ++i) + { + ClangASTType vbase_class_type (clang_type.GetVirtualBaseClassAtIndex(i,NULL)); + + PrivateAutoCompleteMembers (frame, + partial_member_name, + partial_path, + prefix_path, + vbase_class_type.GetCanonicalType(), + matches, + word_complete); + } + } + + // We are in a type parsing child members + const uint32_t num_fields = clang_type.GetNumFields(); + + if (num_fields > 0) + { + for (uint32_t i = 0; i < num_fields; ++i) + { + std::string member_name; + + ClangASTType member_clang_type = clang_type.GetFieldAtIndex (i, member_name, NULL, NULL, NULL); + + if (partial_member_name.empty() || + member_name.find(partial_member_name) == 0) + { + if (member_name == partial_member_name) + { + PrivateAutoComplete (frame, + partial_path, + prefix_path + member_name, // Anything that has been resolved already will be in here + member_clang_type.GetCanonicalType(), + matches, + word_complete); + } + else + { + matches.AppendString (prefix_path + member_name); + } + } + } + } +} + +static void +PrivateAutoComplete (StackFrame *frame, + const std::string &partial_path, + const std::string &prefix_path, // Anything that has been resolved already will be in here + const ClangASTType& clang_type, + StringList &matches, + bool &word_complete) +{ +// printf ("\nPrivateAutoComplete()\n\tprefix_path = '%s'\n\tpartial_path = '%s'\n", prefix_path.c_str(), partial_path.c_str()); + std::string remaining_partial_path; + + const lldb::TypeClass type_class = clang_type.GetTypeClass(); + if (partial_path.empty()) + { + if (clang_type.IsValid()) + { + switch (type_class) + { + default: + case eTypeClassArray: + case eTypeClassBlockPointer: + case eTypeClassBuiltin: + case eTypeClassComplexFloat: + case eTypeClassComplexInteger: + case eTypeClassEnumeration: + case eTypeClassFunction: + case eTypeClassMemberPointer: + case eTypeClassReference: + case eTypeClassTypedef: + case eTypeClassVector: + { + matches.AppendString (prefix_path); + word_complete = matches.GetSize() == 1; + } + break; + + case eTypeClassClass: + case eTypeClassStruct: + case eTypeClassUnion: + if (prefix_path.back() != '.') + matches.AppendString (prefix_path + '.'); + break; + + case eTypeClassObjCObject: + case eTypeClassObjCInterface: + break; + case eTypeClassObjCObjectPointer: + case eTypeClassPointer: + { + bool omit_empty_base_classes = true; + if (clang_type.GetNumChildren (omit_empty_base_classes) > 0) + matches.AppendString (prefix_path + "->"); + else + { + matches.AppendString (prefix_path); + word_complete = true; + } + } + break; + } + } + else + { + if (frame) + { + const bool get_file_globals = true; + + VariableList *variable_list = frame->GetVariableList(get_file_globals); + + const size_t num_variables = variable_list->GetSize(); + for (size_t i=0; i<num_variables; ++i) + { + Variable *variable = variable_list->GetVariableAtIndex(i).get(); + matches.AppendString (variable->GetName().AsCString()); + } + } + } + } + else + { + const char ch = partial_path[0]; + switch (ch) + { + case '*': + if (prefix_path.empty()) + { + PrivateAutoComplete (frame, + partial_path.substr(1), + std::string("*"), + clang_type, + matches, + word_complete); + } + break; + + case '&': + if (prefix_path.empty()) + { + PrivateAutoComplete (frame, + partial_path.substr(1), + std::string("&"), + clang_type, + matches, + word_complete); + } + break; + + case '-': + if (partial_path[1] == '>' && !prefix_path.empty()) + { + switch (type_class) + { + case lldb::eTypeClassPointer: + { + ClangASTType pointee_type(clang_type.GetPointeeType()); + if (partial_path[2]) + { + // If there is more after the "->", then search deeper + PrivateAutoComplete (frame, + partial_path.substr(2), + prefix_path + "->", + pointee_type.GetCanonicalType(), + matches, + word_complete); + } + else + { + // Nothing after the "->", so list all members + PrivateAutoCompleteMembers (frame, + std::string(), + std::string(), + prefix_path + "->", + pointee_type.GetCanonicalType(), + matches, + word_complete); + } + } + default: + break; + } + } + break; + + case '.': + if (clang_type.IsValid()) + { + switch (type_class) + { + case lldb::eTypeClassUnion: + case lldb::eTypeClassStruct: + case lldb::eTypeClassClass: + if (partial_path[1]) + { + // If there is more after the ".", then search deeper + PrivateAutoComplete (frame, + partial_path.substr(1), + prefix_path + ".", + clang_type, + matches, + word_complete); + + } + else + { + // Nothing after the ".", so list all members + PrivateAutoCompleteMembers (frame, + std::string(), + partial_path, + prefix_path + ".", + clang_type, + matches, + word_complete); + } + default: + break; + } + } + break; + default: + if (isalpha(ch) || ch == '_' || ch == '$') + { + const size_t partial_path_len = partial_path.size(); + size_t pos = 1; + while (pos < partial_path_len) + { + const char curr_ch = partial_path[pos]; + if (isalnum(curr_ch) || curr_ch == '_' || curr_ch == '$') + { + ++pos; + continue; + } + break; + } + + std::string token(partial_path, 0, pos); + remaining_partial_path = partial_path.substr(pos); + + if (clang_type.IsValid()) + { + PrivateAutoCompleteMembers (frame, + token, + remaining_partial_path, + prefix_path, + clang_type, + matches, + word_complete); + } + else if (frame) + { + // We haven't found our variable yet + const bool get_file_globals = true; + + VariableList *variable_list = frame->GetVariableList(get_file_globals); + + const size_t num_variables = variable_list->GetSize(); + for (size_t i=0; i<num_variables; ++i) + { + Variable *variable = variable_list->GetVariableAtIndex(i).get(); + const char *variable_name = variable->GetName().AsCString(); + if (strstr(variable_name, token.c_str()) == variable_name) + { + if (strcmp (variable_name, token.c_str()) == 0) + { + Type *variable_type = variable->GetType(); + if (variable_type) + { + ClangASTType variable_clang_type (variable_type->GetClangForwardType()); + PrivateAutoComplete (frame, + remaining_partial_path, + prefix_path + token, // Anything that has been resolved already will be in here + variable_clang_type.GetCanonicalType(), + matches, + word_complete); + } + else + { + matches.AppendString (prefix_path + variable_name); + } + } + else if (remaining_partial_path.empty()) + { + matches.AppendString (prefix_path + variable_name); + } + } + } + } + } + break; + } + } +} + + + +size_t +Variable::AutoComplete (const ExecutionContext &exe_ctx, + const char *partial_path_cstr, + StringList &matches, + bool &word_complete) +{ + word_complete = false; + std::string partial_path; + std::string prefix_path; + ClangASTType clang_type; + if (partial_path_cstr && partial_path_cstr[0]) + partial_path = partial_path_cstr; + + PrivateAutoComplete (exe_ctx.GetFramePtr(), + partial_path, + prefix_path, + clang_type, + matches, + word_complete); + + return matches.GetSize(); +} + |