diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Target/StackFrame.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Target/StackFrame.cpp | 1449 |
1 files changed, 1449 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Target/StackFrame.cpp b/contrib/llvm/tools/lldb/source/Target/StackFrame.cpp new file mode 100644 index 0000000..3c4c43d --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Target/StackFrame.cpp @@ -0,0 +1,1449 @@ +//===-- StackFrame.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/lldb-python.h" + +#include "lldb/Target/StackFrame.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Module.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Disassembler.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectVariable.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SymbolContextScope.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; + +// The first bits in the flags are reserved for the SymbolContext::Scope bits +// so we know if we have tried to look up information in our internal symbol +// context (m_sc) already. +#define RESOLVED_FRAME_CODE_ADDR (uint32_t(eSymbolContextEverything + 1)) +#define RESOLVED_FRAME_ID_SYMBOL_SCOPE (RESOLVED_FRAME_CODE_ADDR << 1) +#define GOT_FRAME_BASE (RESOLVED_FRAME_ID_SYMBOL_SCOPE << 1) +#define RESOLVED_VARIABLES (GOT_FRAME_BASE << 1) +#define RESOLVED_GLOBAL_VARIABLES (RESOLVED_VARIABLES << 1) + +StackFrame::StackFrame (const ThreadSP &thread_sp, + user_id_t frame_idx, + user_id_t unwind_frame_index, + addr_t cfa, + addr_t pc, + const SymbolContext *sc_ptr) : + m_thread_wp (thread_sp), + m_frame_index (frame_idx), + m_concrete_frame_index (unwind_frame_index), + m_reg_context_sp (), + m_id (pc, cfa, NULL), + m_frame_code_addr (pc), + m_sc (), + m_flags (), + m_frame_base (), + m_frame_base_error (), + m_variable_list_sp (), + m_variable_list_value_objects (), + m_disassembly () +{ + if (sc_ptr != NULL) + { + m_sc = *sc_ptr; + m_flags.Set(m_sc.GetResolvedMask ()); + } +} + +StackFrame::StackFrame (const ThreadSP &thread_sp, + user_id_t frame_idx, + user_id_t unwind_frame_index, + const RegisterContextSP ®_context_sp, + addr_t cfa, + addr_t pc, + const SymbolContext *sc_ptr) : + m_thread_wp (thread_sp), + m_frame_index (frame_idx), + m_concrete_frame_index (unwind_frame_index), + m_reg_context_sp (reg_context_sp), + m_id (pc, cfa, NULL), + m_frame_code_addr (pc), + m_sc (), + m_flags (), + m_frame_base (), + m_frame_base_error (), + m_variable_list_sp (), + m_variable_list_value_objects (), + m_disassembly () +{ + if (sc_ptr != NULL) + { + m_sc = *sc_ptr; + m_flags.Set(m_sc.GetResolvedMask ()); + } + + if (reg_context_sp && !m_sc.target_sp) + { + m_sc.target_sp = reg_context_sp->CalculateTarget(); + if (m_sc.target_sp) + m_flags.Set (eSymbolContextTarget); + } +} + +StackFrame::StackFrame (const ThreadSP &thread_sp, + user_id_t frame_idx, + user_id_t unwind_frame_index, + const RegisterContextSP ®_context_sp, + addr_t cfa, + const Address& pc_addr, + const SymbolContext *sc_ptr) : + m_thread_wp (thread_sp), + m_frame_index (frame_idx), + m_concrete_frame_index (unwind_frame_index), + m_reg_context_sp (reg_context_sp), + m_id (pc_addr.GetLoadAddress (thread_sp->CalculateTarget().get()), cfa, NULL), + m_frame_code_addr (pc_addr), + m_sc (), + m_flags (), + m_frame_base (), + m_frame_base_error (), + m_variable_list_sp (), + m_variable_list_value_objects (), + m_disassembly () +{ + if (sc_ptr != NULL) + { + m_sc = *sc_ptr; + m_flags.Set(m_sc.GetResolvedMask ()); + } + + if (m_sc.target_sp.get() == NULL && reg_context_sp) + { + m_sc.target_sp = reg_context_sp->CalculateTarget(); + if (m_sc.target_sp) + m_flags.Set (eSymbolContextTarget); + } + + ModuleSP pc_module_sp (pc_addr.GetModule()); + if (!m_sc.module_sp || m_sc.module_sp != pc_module_sp) + { + if (pc_module_sp) + { + m_sc.module_sp = pc_module_sp; + m_flags.Set (eSymbolContextModule); + } + else + { + m_sc.module_sp.reset(); + } + } +} + + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +StackFrame::~StackFrame() +{ +} + +StackID& +StackFrame::GetStackID() +{ + // Make sure we have resolved the StackID object's symbol context scope if + // we already haven't looked it up. + + if (m_flags.IsClear (RESOLVED_FRAME_ID_SYMBOL_SCOPE)) + { + if (m_id.GetSymbolContextScope ()) + { + // We already have a symbol context scope, we just don't have our + // flag bit set. + m_flags.Set (RESOLVED_FRAME_ID_SYMBOL_SCOPE); + } + else + { + // Calculate the frame block and use this for the stack ID symbol + // context scope if we have one. + SymbolContextScope *scope = GetFrameBlock (); + if (scope == NULL) + { + // We don't have a block, so use the symbol + if (m_flags.IsClear (eSymbolContextSymbol)) + GetSymbolContext (eSymbolContextSymbol); + + // It is ok if m_sc.symbol is NULL here + scope = m_sc.symbol; + } + // Set the symbol context scope (the accessor will set the + // RESOLVED_FRAME_ID_SYMBOL_SCOPE bit in m_flags). + SetSymbolContextScope (scope); + } + } + return m_id; +} + +uint32_t +StackFrame::GetFrameIndex () const +{ + ThreadSP thread_sp = GetThread(); + if (thread_sp) + return thread_sp->GetStackFrameList()->GetVisibleStackFrameIndex(m_frame_index); + else + return m_frame_index; +} + +void +StackFrame::SetSymbolContextScope (SymbolContextScope *symbol_scope) +{ + m_flags.Set (RESOLVED_FRAME_ID_SYMBOL_SCOPE); + m_id.SetSymbolContextScope (symbol_scope); +} + +const Address& +StackFrame::GetFrameCodeAddress() +{ + if (m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR) && !m_frame_code_addr.IsSectionOffset()) + { + m_flags.Set (RESOLVED_FRAME_CODE_ADDR); + + // Resolve the PC into a temporary address because if ResolveLoadAddress + // fails to resolve the address, it will clear the address object... + ThreadSP thread_sp (GetThread()); + if (thread_sp) + { + TargetSP target_sp (thread_sp->CalculateTarget()); + if (target_sp) + { + if (m_frame_code_addr.SetOpcodeLoadAddress (m_frame_code_addr.GetOffset(), target_sp.get())) + { + ModuleSP module_sp (m_frame_code_addr.GetModule()); + if (module_sp) + { + m_sc.module_sp = module_sp; + m_flags.Set(eSymbolContextModule); + } + } + } + } + } + return m_frame_code_addr; +} + +void +StackFrame::ChangePC (addr_t pc) +{ + m_frame_code_addr.SetRawAddress(pc); + m_sc.Clear(false); + m_flags.Reset(0); + ThreadSP thread_sp (GetThread()); + if (thread_sp) + thread_sp->ClearStackFrames (); +} + +const char * +StackFrame::Disassemble () +{ + if (m_disassembly.GetSize() == 0) + { + ExecutionContext exe_ctx (shared_from_this()); + Target *target = exe_ctx.GetTargetPtr(); + if (target) + { + const char *plugin_name = NULL; + const char *flavor = NULL; + Disassembler::Disassemble (target->GetDebugger(), + target->GetArchitecture(), + plugin_name, + flavor, + exe_ctx, + 0, + 0, + 0, + m_disassembly); + } + if (m_disassembly.GetSize() == 0) + return NULL; + } + return m_disassembly.GetData(); +} + +Block * +StackFrame::GetFrameBlock () +{ + if (m_sc.block == NULL && m_flags.IsClear (eSymbolContextBlock)) + GetSymbolContext (eSymbolContextBlock); + + if (m_sc.block) + { + Block *inline_block = m_sc.block->GetContainingInlinedBlock(); + if (inline_block) + { + // Use the block with the inlined function info + // as the frame block we want this frame to have only the variables + // for the inlined function and its non-inlined block child blocks. + return inline_block; + } + else + { + // This block is not contained withing any inlined function blocks + // with so we want to use the top most function block. + return &m_sc.function->GetBlock (false); + } + } + return NULL; +} + +//---------------------------------------------------------------------- +// Get the symbol context if we already haven't done so by resolving the +// PC address as much as possible. This way when we pass around a +// StackFrame object, everyone will have as much information as +// possible and no one will ever have to look things up manually. +//---------------------------------------------------------------------- +const SymbolContext& +StackFrame::GetSymbolContext (uint32_t resolve_scope) +{ + // Copy our internal symbol context into "sc". + if ((m_flags.Get() & resolve_scope) != resolve_scope) + { + uint32_t resolved = 0; + + // If the target was requested add that: + if (!m_sc.target_sp) + { + m_sc.target_sp = CalculateTarget(); + if (m_sc.target_sp) + resolved |= eSymbolContextTarget; + } + + + // Resolve our PC to section offset if we haven't alreday done so + // and if we don't have a module. The resolved address section will + // contain the module to which it belongs + if (!m_sc.module_sp && m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR)) + GetFrameCodeAddress(); + + // If this is not frame zero, then we need to subtract 1 from the PC + // value when doing address lookups since the PC will be on the + // instruction following the function call instruction... + + Address lookup_addr(GetFrameCodeAddress()); + if (m_frame_index > 0 && lookup_addr.IsValid()) + { + addr_t offset = lookup_addr.GetOffset(); + if (offset > 0) + lookup_addr.SetOffset(offset - 1); + } + + + if (m_sc.module_sp) + { + // We have something in our stack frame symbol context, lets check + // if we haven't already tried to lookup one of those things. If we + // haven't then we will do the query. + + uint32_t actual_resolve_scope = 0; + + if (resolve_scope & eSymbolContextCompUnit) + { + if (m_flags.IsClear (eSymbolContextCompUnit)) + { + if (m_sc.comp_unit) + resolved |= eSymbolContextCompUnit; + else + actual_resolve_scope |= eSymbolContextCompUnit; + } + } + + if (resolve_scope & eSymbolContextFunction) + { + if (m_flags.IsClear (eSymbolContextFunction)) + { + if (m_sc.function) + resolved |= eSymbolContextFunction; + else + actual_resolve_scope |= eSymbolContextFunction; + } + } + + if (resolve_scope & eSymbolContextBlock) + { + if (m_flags.IsClear (eSymbolContextBlock)) + { + if (m_sc.block) + resolved |= eSymbolContextBlock; + else + actual_resolve_scope |= eSymbolContextBlock; + } + } + + if (resolve_scope & eSymbolContextSymbol) + { + if (m_flags.IsClear (eSymbolContextSymbol)) + { + if (m_sc.symbol) + resolved |= eSymbolContextSymbol; + else + actual_resolve_scope |= eSymbolContextSymbol; + } + } + + if (resolve_scope & eSymbolContextLineEntry) + { + if (m_flags.IsClear (eSymbolContextLineEntry)) + { + if (m_sc.line_entry.IsValid()) + resolved |= eSymbolContextLineEntry; + else + actual_resolve_scope |= eSymbolContextLineEntry; + } + } + + if (actual_resolve_scope) + { + // We might be resolving less information than what is already + // in our current symbol context so resolve into a temporary + // symbol context "sc" so we don't clear out data we have + // already found in "m_sc" + SymbolContext sc; + // Set flags that indicate what we have tried to resolve + resolved |= m_sc.module_sp->ResolveSymbolContextForAddress (lookup_addr, actual_resolve_scope, sc); + // Only replace what we didn't already have as we may have + // information for an inlined function scope that won't match + // what a standard lookup by address would match + if ((resolved & eSymbolContextCompUnit) && m_sc.comp_unit == NULL) + m_sc.comp_unit = sc.comp_unit; + if ((resolved & eSymbolContextFunction) && m_sc.function == NULL) + m_sc.function = sc.function; + if ((resolved & eSymbolContextBlock) && m_sc.block == NULL) + m_sc.block = sc.block; + if ((resolved & eSymbolContextSymbol) && m_sc.symbol == NULL) + m_sc.symbol = sc.symbol; + if ((resolved & eSymbolContextLineEntry) && !m_sc.line_entry.IsValid()) + { + m_sc.line_entry = sc.line_entry; + if (m_sc.target_sp) + { + // Be sure to apply and file remappings to our file and line + // entries when handing out a line entry + FileSpec new_file_spec; + if (m_sc.target_sp->GetSourcePathMap().FindFile (m_sc.line_entry.file, new_file_spec)) + m_sc.line_entry.file = new_file_spec; + } + } + } + } + else + { + // If we don't have a module, then we can't have the compile unit, + // function, block, line entry or symbol, so we can safely call + // ResolveSymbolContextForAddress with our symbol context member m_sc. + if (m_sc.target_sp) + { + resolved |= m_sc.target_sp->GetImages().ResolveSymbolContextForAddress (lookup_addr, resolve_scope, m_sc); + } + } + + // Update our internal flags so we remember what we have tried to locate so + // we don't have to keep trying when more calls to this function are made. + // We might have dug up more information that was requested (for example + // if we were asked to only get the block, we will have gotten the + // compile unit, and function) so set any additional bits that we resolved + m_flags.Set (resolve_scope | resolved); + } + + // Return the symbol context with everything that was possible to resolve + // resolved. + return m_sc; +} + + +VariableList * +StackFrame::GetVariableList (bool get_file_globals) +{ + if (m_flags.IsClear(RESOLVED_VARIABLES)) + { + m_flags.Set(RESOLVED_VARIABLES); + + Block *frame_block = GetFrameBlock(); + + if (frame_block) + { + const bool get_child_variables = true; + const bool can_create = true; + const bool stop_if_child_block_is_inlined_function = true; + m_variable_list_sp.reset(new VariableList()); + frame_block->AppendBlockVariables(can_create, get_child_variables, stop_if_child_block_is_inlined_function, m_variable_list_sp.get()); + } + } + + if (m_flags.IsClear(RESOLVED_GLOBAL_VARIABLES) && + get_file_globals) + { + m_flags.Set(RESOLVED_GLOBAL_VARIABLES); + + if (m_flags.IsClear (eSymbolContextCompUnit)) + GetSymbolContext (eSymbolContextCompUnit); + + if (m_sc.comp_unit) + { + VariableListSP global_variable_list_sp (m_sc.comp_unit->GetVariableList(true)); + if (m_variable_list_sp) + m_variable_list_sp->AddVariables (global_variable_list_sp.get()); + else + m_variable_list_sp = global_variable_list_sp; + } + } + + return m_variable_list_sp.get(); +} + +VariableListSP +StackFrame::GetInScopeVariableList (bool get_file_globals) +{ + VariableListSP var_list_sp(new VariableList); + GetSymbolContext (eSymbolContextCompUnit | eSymbolContextBlock); + + if (m_sc.block) + { + const bool can_create = true; + const bool get_parent_variables = true; + const bool stop_if_block_is_inlined_function = true; + m_sc.block->AppendVariables (can_create, + get_parent_variables, + stop_if_block_is_inlined_function, + var_list_sp.get()); + } + + if (m_sc.comp_unit) + { + VariableListSP global_variable_list_sp (m_sc.comp_unit->GetVariableList(true)); + if (global_variable_list_sp) + var_list_sp->AddVariables (global_variable_list_sp.get()); + } + + return var_list_sp; +} + + +ValueObjectSP +StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, + DynamicValueType use_dynamic, + uint32_t options, + VariableSP &var_sp, + Error &error) +{ + + if (var_expr_cstr && var_expr_cstr[0]) + { + const bool check_ptr_vs_member = (options & eExpressionPathOptionCheckPtrVsMember) != 0; + const bool no_fragile_ivar = (options & eExpressionPathOptionsNoFragileObjcIvar) != 0; + const bool no_synth_child = (options & eExpressionPathOptionsNoSyntheticChildren) != 0; + //const bool no_synth_array = (options & eExpressionPathOptionsNoSyntheticArrayRange) != 0; + error.Clear(); + bool deref = false; + bool address_of = false; + ValueObjectSP valobj_sp; + const bool get_file_globals = true; + // When looking up a variable for an expression, we need only consider the + // variables that are in scope. + VariableListSP var_list_sp (GetInScopeVariableList (get_file_globals)); + VariableList *variable_list = var_list_sp.get(); + + if (variable_list) + { + // If first character is a '*', then show pointer contents + const char *var_expr = var_expr_cstr; + if (var_expr[0] == '*') + { + deref = true; + var_expr++; // Skip the '*' + } + else if (var_expr[0] == '&') + { + address_of = true; + var_expr++; // Skip the '&' + } + + std::string var_path (var_expr); + size_t separator_idx = var_path.find_first_of(".-[=+~|&^%#@!/?,<>{}"); + StreamString var_expr_path_strm; + + ConstString name_const_string; + if (separator_idx == std::string::npos) + name_const_string.SetCString (var_path.c_str()); + else + name_const_string.SetCStringWithLength (var_path.c_str(), separator_idx); + + var_sp = variable_list->FindVariable(name_const_string); + + bool synthetically_added_instance_object = false; + + if (var_sp) + { + var_path.erase (0, name_const_string.GetLength ()); + } + else if (options & eExpressionPathOptionsAllowDirectIVarAccess) + { + // Check for direct ivars access which helps us with implicit + // access to ivars with the "this->" or "self->" + GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock); + lldb::LanguageType method_language = eLanguageTypeUnknown; + bool is_instance_method = false; + ConstString method_object_name; + if (m_sc.GetFunctionMethodInfo (method_language, is_instance_method, method_object_name)) + { + if (is_instance_method && method_object_name) + { + var_sp = variable_list->FindVariable(method_object_name); + if (var_sp) + { + separator_idx = 0; + var_path.insert(0, "->"); + synthetically_added_instance_object = true; + } + } + } + } + + if (var_sp) + { + valobj_sp = GetValueObjectForFrameVariable (var_sp, use_dynamic); + if (!valobj_sp) + return valobj_sp; + + // We are dumping at least one child + while (separator_idx != std::string::npos) + { + // Calculate the next separator index ahead of time + ValueObjectSP child_valobj_sp; + const char separator_type = var_path[0]; + switch (separator_type) + { + + case '-': + if (var_path.size() >= 2 && var_path[1] != '>') + return ValueObjectSP(); + + if (no_fragile_ivar) + { + // Make sure we aren't trying to deref an objective + // C ivar if this is not allowed + const uint32_t pointer_type_flags = valobj_sp->GetClangType().GetTypeInfo (NULL); + if ((pointer_type_flags & ClangASTType::eTypeIsObjC) && + (pointer_type_flags & ClangASTType::eTypeIsPointer)) + { + // This was an objective C object pointer and + // it was requested we skip any fragile ivars + // so return nothing here + return ValueObjectSP(); + } + } + var_path.erase (0, 1); // Remove the '-' + // Fall through + case '.': + { + const bool expr_is_ptr = var_path[0] == '>'; + + var_path.erase (0, 1); // Remove the '.' or '>' + separator_idx = var_path.find_first_of(".-["); + ConstString child_name; + if (separator_idx == std::string::npos) + child_name.SetCString (var_path.c_str()); + else + child_name.SetCStringWithLength(var_path.c_str(), separator_idx); + + if (check_ptr_vs_member) + { + // We either have a pointer type and need to verify + // valobj_sp is a pointer, or we have a member of a + // class/union/struct being accessed with the . syntax + // and need to verify we don't have a pointer. + const bool actual_is_ptr = valobj_sp->IsPointerType (); + + if (actual_is_ptr != expr_is_ptr) + { + // Incorrect use of "." with a pointer, or "->" with + // a class/union/struct instance or reference. + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + if (actual_is_ptr) + error.SetErrorStringWithFormat ("\"%s\" is a pointer and . was used to attempt to access \"%s\". Did you mean \"%s->%s\"?", + var_expr_path_strm.GetString().c_str(), + child_name.GetCString(), + var_expr_path_strm.GetString().c_str(), + var_path.c_str()); + else + error.SetErrorStringWithFormat ("\"%s\" is not a pointer and -> was used to attempt to access \"%s\". Did you mean \"%s.%s\"?", + var_expr_path_strm.GetString().c_str(), + child_name.GetCString(), + var_expr_path_strm.GetString().c_str(), + var_path.c_str()); + return ValueObjectSP(); + } + } + child_valobj_sp = valobj_sp->GetChildMemberWithName (child_name, true); + if (!child_valobj_sp) + { + if (no_synth_child == false) + { + child_valobj_sp = valobj_sp->GetSyntheticValue(); + if (child_valobj_sp) + child_valobj_sp = child_valobj_sp->GetChildMemberWithName (child_name, true); + } + + if (no_synth_child || !child_valobj_sp) + { + // No child member with name "child_name" + if (synthetically_added_instance_object) + { + // We added a "this->" or "self->" to the beginning of the expression + // and this is the first pointer ivar access, so just return the normal + // error + error.SetErrorStringWithFormat("no variable or instance variable named '%s' found in this frame", + name_const_string.GetCString()); + } + else + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + if (child_name) + { + error.SetErrorStringWithFormat ("\"%s\" is not a member of \"(%s) %s\"", + child_name.GetCString(), + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + else + { + error.SetErrorStringWithFormat ("incomplete expression path after \"%s\" in \"%s\"", + var_expr_path_strm.GetString().c_str(), + var_expr_cstr); + } + } + return ValueObjectSP(); + } + } + synthetically_added_instance_object = false; + // Remove the child name from the path + var_path.erase(0, child_name.GetLength()); + if (use_dynamic != eNoDynamicValues) + { + ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(use_dynamic)); + if (dynamic_value_sp) + child_valobj_sp = dynamic_value_sp; + } + } + break; + + case '[': + // Array member access, or treating pointer as an array + if (var_path.size() > 2) // Need at least two brackets and a number + { + char *end = NULL; + long child_index = ::strtol (&var_path[1], &end, 0); + if (end && *end == ']' + && *(end-1) != '[') // this code forces an error in the case of arr[]. as bitfield[] is not a good syntax we're good to go + { + if (valobj_sp->GetClangType().IsPointerToScalarType() && deref) + { + // what we have is *ptr[low]. the most similar C++ syntax is to deref ptr + // and extract bit low out of it. reading array item low + // would be done by saying ptr[low], without a deref * sign + Error error; + ValueObjectSP temp(valobj_sp->Dereference(error)); + if (error.Fail()) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("could not dereference \"(%s) %s\"", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + return ValueObjectSP(); + } + valobj_sp = temp; + deref = false; + } + else if (valobj_sp->GetClangType().IsArrayOfScalarType() && deref) + { + // what we have is *arr[low]. the most similar C++ syntax is to get arr[0] + // (an operation that is equivalent to deref-ing arr) + // and extract bit low out of it. reading array item low + // would be done by saying arr[low], without a deref * sign + Error error; + ValueObjectSP temp(valobj_sp->GetChildAtIndex (0, true)); + if (error.Fail()) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("could not get item 0 for \"(%s) %s\"", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + return ValueObjectSP(); + } + valobj_sp = temp; + deref = false; + } + + bool is_incomplete_array = false; + if (valobj_sp->IsPointerType ()) + { + bool is_objc_pointer = true; + + if (valobj_sp->GetClangType().GetMinimumLanguage() != eLanguageTypeObjC) + is_objc_pointer = false; + else if (!valobj_sp->GetClangType().IsPointerType()) + is_objc_pointer = false; + + if (no_synth_child && is_objc_pointer) + { + error.SetErrorStringWithFormat("\"(%s) %s\" is an Objective-C pointer, and cannot be subscripted", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + + return ValueObjectSP(); + } + else if (is_objc_pointer) + { + // dereferencing ObjC variables is not valid.. so let's try and recur to synthetic children + ValueObjectSP synthetic = valobj_sp->GetSyntheticValue(); + if (synthetic.get() == NULL /* no synthetic */ + || synthetic == valobj_sp) /* synthetic is the same as the original object */ + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("\"(%s) %s\" is not an array type", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + else if (child_index >= synthetic->GetNumChildren() /* synthetic does not have that many values */) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"", + child_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + else + { + child_valobj_sp = synthetic->GetChildAtIndex(child_index, true); + if (!child_valobj_sp) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"", + child_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + } + } + else + { + child_valobj_sp = valobj_sp->GetSyntheticArrayMemberFromPointer (child_index, true); + if (!child_valobj_sp) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("failed to use pointer as array for index %ld for \"(%s) %s\"", + child_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + } + } + else if (valobj_sp->GetClangType().IsArrayType (NULL, NULL, &is_incomplete_array)) + { + // Pass false to dynamic_value here so we can tell the difference between + // no dynamic value and no member of this type... + child_valobj_sp = valobj_sp->GetChildAtIndex (child_index, true); + if (!child_valobj_sp && (is_incomplete_array || no_synth_child == false)) + child_valobj_sp = valobj_sp->GetSyntheticArrayMember (child_index, true); + + if (!child_valobj_sp) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"", + child_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + } + else if (valobj_sp->GetClangType().IsScalarType()) + { + // this is a bitfield asking to display just one bit + child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild(child_index, child_index, true); + if (!child_valobj_sp) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("bitfield range %ld-%ld is not valid for \"(%s) %s\"", + child_index, child_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + } + else + { + ValueObjectSP synthetic = valobj_sp->GetSyntheticValue(); + if (no_synth_child /* synthetic is forbidden */ || + synthetic.get() == NULL /* no synthetic */ + || synthetic == valobj_sp) /* synthetic is the same as the original object */ + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("\"(%s) %s\" is not an array type", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + else if (child_index >= synthetic->GetNumChildren() /* synthetic does not have that many values */) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"", + child_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + else + { + child_valobj_sp = synthetic->GetChildAtIndex(child_index, true); + if (!child_valobj_sp) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"", + child_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + } + } + + if (!child_valobj_sp) + { + // Invalid array index... + return ValueObjectSP(); + } + + // Erase the array member specification '[%i]' where + // %i is the array index + var_path.erase(0, (end - var_path.c_str()) + 1); + separator_idx = var_path.find_first_of(".-["); + if (use_dynamic != eNoDynamicValues) + { + ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(use_dynamic)); + if (dynamic_value_sp) + child_valobj_sp = dynamic_value_sp; + } + // Break out early from the switch since we were + // able to find the child member + break; + } + else if (end && *end == '-') + { + // this is most probably a BitField, let's take a look + char *real_end = NULL; + long final_index = ::strtol (end+1, &real_end, 0); + bool expand_bitfield = true; + if (real_end && *real_end == ']') + { + // if the format given is [high-low], swap range + if (child_index > final_index) + { + long temp = child_index; + child_index = final_index; + final_index = temp; + } + + if (valobj_sp->GetClangType().IsPointerToScalarType() && deref) + { + // what we have is *ptr[low-high]. the most similar C++ syntax is to deref ptr + // and extract bits low thru high out of it. reading array items low thru high + // would be done by saying ptr[low-high], without a deref * sign + Error error; + ValueObjectSP temp(valobj_sp->Dereference(error)); + if (error.Fail()) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("could not dereference \"(%s) %s\"", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + return ValueObjectSP(); + } + valobj_sp = temp; + deref = false; + } + else if (valobj_sp->GetClangType().IsArrayOfScalarType() && deref) + { + // what we have is *arr[low-high]. the most similar C++ syntax is to get arr[0] + // (an operation that is equivalent to deref-ing arr) + // and extract bits low thru high out of it. reading array items low thru high + // would be done by saying arr[low-high], without a deref * sign + Error error; + ValueObjectSP temp(valobj_sp->GetChildAtIndex (0, true)); + if (error.Fail()) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("could not get item 0 for \"(%s) %s\"", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + return ValueObjectSP(); + } + valobj_sp = temp; + deref = false; + } + /*else if (valobj_sp->IsArrayType() || valobj_sp->IsPointerType()) + { + child_valobj_sp = valobj_sp->GetSyntheticArrayRangeChild(child_index, final_index, true); + expand_bitfield = false; + if (!child_valobj_sp) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("array range %i-%i is not valid for \"(%s) %s\"", + child_index, final_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + }*/ + + if (expand_bitfield) + { + child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild(child_index, final_index, true); + if (!child_valobj_sp) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("bitfield range %ld-%ld is not valid for \"(%s) %s\"", + child_index, final_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + } + } + + if (!child_valobj_sp) + { + // Invalid bitfield range... + return ValueObjectSP(); + } + + // Erase the bitfield member specification '[%i-%i]' where + // %i is the index + var_path.erase(0, (real_end - var_path.c_str()) + 1); + separator_idx = var_path.find_first_of(".-["); + if (use_dynamic != eNoDynamicValues) + { + ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(use_dynamic)); + if (dynamic_value_sp) + child_valobj_sp = dynamic_value_sp; + } + // Break out early from the switch since we were + // able to find the child member + break; + + } + } + else + { + error.SetErrorStringWithFormat("invalid square bracket encountered after \"%s\" in \"%s\"", + var_expr_path_strm.GetString().c_str(), + var_path.c_str()); + } + return ValueObjectSP(); + + default: + // Failure... + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("unexpected char '%c' encountered after \"%s\" in \"%s\"", + separator_type, + var_expr_path_strm.GetString().c_str(), + var_path.c_str()); + + return ValueObjectSP(); + } + } + + if (child_valobj_sp) + valobj_sp = child_valobj_sp; + + if (var_path.empty()) + break; + + } + if (valobj_sp) + { + if (deref) + { + ValueObjectSP deref_valobj_sp (valobj_sp->Dereference(error)); + valobj_sp = deref_valobj_sp; + } + else if (address_of) + { + ValueObjectSP address_of_valobj_sp (valobj_sp->AddressOf(error)); + valobj_sp = address_of_valobj_sp; + } + } + return valobj_sp; + } + else + { + error.SetErrorStringWithFormat("no variable named '%s' found in this frame", + name_const_string.GetCString()); + } + } + } + else + { + error.SetErrorStringWithFormat("invalid variable path '%s'", var_expr_cstr); + } + return ValueObjectSP(); +} + +bool +StackFrame::GetFrameBaseValue (Scalar &frame_base, Error *error_ptr) +{ + if (m_flags.IsClear(GOT_FRAME_BASE)) + { + if (m_sc.function) + { + m_frame_base.Clear(); + m_frame_base_error.Clear(); + + m_flags.Set(GOT_FRAME_BASE); + ExecutionContext exe_ctx (shared_from_this()); + Value expr_value; + addr_t loclist_base_addr = LLDB_INVALID_ADDRESS; + if (m_sc.function->GetFrameBaseExpression().IsLocationList()) + loclist_base_addr = m_sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress (exe_ctx.GetTargetPtr()); + + if (m_sc.function->GetFrameBaseExpression().Evaluate(&exe_ctx, NULL, NULL, NULL, loclist_base_addr, NULL, expr_value, &m_frame_base_error) == false) + { + // We should really have an error if evaluate returns, but in case + // we don't, lets set the error to something at least. + if (m_frame_base_error.Success()) + m_frame_base_error.SetErrorString("Evaluation of the frame base expression failed."); + } + else + { + m_frame_base = expr_value.ResolveValue(&exe_ctx); + } + } + else + { + m_frame_base_error.SetErrorString ("No function in symbol context."); + } + } + + if (m_frame_base_error.Success()) + frame_base = m_frame_base; + + if (error_ptr) + *error_ptr = m_frame_base_error; + return m_frame_base_error.Success(); +} + +RegisterContextSP +StackFrame::GetRegisterContext () +{ + if (!m_reg_context_sp) + { + ThreadSP thread_sp (GetThread()); + if (thread_sp) + m_reg_context_sp = thread_sp->CreateRegisterContextForFrame (this); + } + return m_reg_context_sp; +} + +bool +StackFrame::HasDebugInformation () +{ + GetSymbolContext (eSymbolContextLineEntry); + return m_sc.line_entry.IsValid(); +} + + +ValueObjectSP +StackFrame::GetValueObjectForFrameVariable (const VariableSP &variable_sp, DynamicValueType use_dynamic) +{ + ValueObjectSP valobj_sp; + VariableList *var_list = GetVariableList (true); + if (var_list) + { + // Make sure the variable is a frame variable + const uint32_t var_idx = var_list->FindIndexForVariable (variable_sp.get()); + const uint32_t num_variables = var_list->GetSize(); + if (var_idx < num_variables) + { + valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex (var_idx); + if (valobj_sp.get() == NULL) + { + if (m_variable_list_value_objects.GetSize() < num_variables) + m_variable_list_value_objects.Resize(num_variables); + valobj_sp = ValueObjectVariable::Create (this, variable_sp); + m_variable_list_value_objects.SetValueObjectAtIndex (var_idx, valobj_sp); + } + } + } + if (use_dynamic != eNoDynamicValues && valobj_sp) + { + ValueObjectSP dynamic_sp = valobj_sp->GetDynamicValue (use_dynamic); + if (dynamic_sp) + return dynamic_sp; + } + return valobj_sp; +} + +ValueObjectSP +StackFrame::TrackGlobalVariable (const VariableSP &variable_sp, DynamicValueType use_dynamic) +{ + // Check to make sure we aren't already tracking this variable? + ValueObjectSP valobj_sp (GetValueObjectForFrameVariable (variable_sp, use_dynamic)); + if (!valobj_sp) + { + // We aren't already tracking this global + VariableList *var_list = GetVariableList (true); + // If this frame has no variables, create a new list + if (var_list == NULL) + m_variable_list_sp.reset (new VariableList()); + + // Add the global/static variable to this frame + m_variable_list_sp->AddVariable (variable_sp); + + // Now make a value object for it so we can track its changes + valobj_sp = GetValueObjectForFrameVariable (variable_sp, use_dynamic); + } + return valobj_sp; +} + +bool +StackFrame::IsInlined () +{ + if (m_sc.block == NULL) + GetSymbolContext (eSymbolContextBlock); + if (m_sc.block) + return m_sc.block->GetContainingInlinedBlock() != NULL; + return false; +} + +TargetSP +StackFrame::CalculateTarget () +{ + TargetSP target_sp; + ThreadSP thread_sp(GetThread()); + if (thread_sp) + { + ProcessSP process_sp (thread_sp->CalculateProcess()); + if (process_sp) + target_sp = process_sp->CalculateTarget(); + } + return target_sp; +} + +ProcessSP +StackFrame::CalculateProcess () +{ + ProcessSP process_sp; + ThreadSP thread_sp(GetThread()); + if (thread_sp) + process_sp = thread_sp->CalculateProcess(); + return process_sp; +} + +ThreadSP +StackFrame::CalculateThread () +{ + return GetThread(); +} + +StackFrameSP +StackFrame::CalculateStackFrame () +{ + return shared_from_this(); +} + + +void +StackFrame::CalculateExecutionContext (ExecutionContext &exe_ctx) +{ + exe_ctx.SetContext (shared_from_this()); +} + +void +StackFrame::DumpUsingSettingsFormat (Stream *strm) +{ + if (strm == NULL) + return; + + GetSymbolContext(eSymbolContextEverything); + ExecutionContext exe_ctx (shared_from_this()); + StreamString s; + const char *frame_format = NULL; + Target *target = exe_ctx.GetTargetPtr(); + if (target) + frame_format = target->GetDebugger().GetFrameFormat(); + if (frame_format && Debugger::FormatPrompt (frame_format, &m_sc, &exe_ctx, NULL, s)) + { + strm->Write(s.GetData(), s.GetSize()); + } + else + { + Dump (strm, true, false); + strm->EOL(); + } +} + +void +StackFrame::Dump (Stream *strm, bool show_frame_index, bool show_fullpaths) +{ + if (strm == NULL) + return; + + if (show_frame_index) + strm->Printf("frame #%u: ", m_frame_index); + ExecutionContext exe_ctx (shared_from_this()); + Target *target = exe_ctx.GetTargetPtr(); + strm->Printf("0x%0*" PRIx64 " ", + target ? (target->GetArchitecture().GetAddressByteSize() * 2) : 16, + GetFrameCodeAddress().GetLoadAddress(target)); + GetSymbolContext(eSymbolContextEverything); + const bool show_module = true; + const bool show_inline = true; + m_sc.DumpStopContext (strm, + exe_ctx.GetBestExecutionContextScope(), + GetFrameCodeAddress(), + show_fullpaths, + show_module, + show_inline); +} + +void +StackFrame::UpdateCurrentFrameFromPreviousFrame (StackFrame &prev_frame) +{ + assert (GetStackID() == prev_frame.GetStackID()); // TODO: remove this after some testing + m_variable_list_sp = prev_frame.m_variable_list_sp; + m_variable_list_value_objects.Swap (prev_frame.m_variable_list_value_objects); + if (!m_disassembly.GetString().empty()) + m_disassembly.GetString().swap (m_disassembly.GetString()); +} + + +void +StackFrame::UpdatePreviousFrameFromCurrentFrame (StackFrame &curr_frame) +{ + assert (GetStackID() == curr_frame.GetStackID()); // TODO: remove this after some testing + m_id.SetPC (curr_frame.m_id.GetPC()); // Update the Stack ID PC value + assert (GetThread() == curr_frame.GetThread()); + m_frame_index = curr_frame.m_frame_index; + m_concrete_frame_index = curr_frame.m_concrete_frame_index; + m_reg_context_sp = curr_frame.m_reg_context_sp; + m_frame_code_addr = curr_frame.m_frame_code_addr; + assert (m_sc.target_sp.get() == NULL || curr_frame.m_sc.target_sp.get() == NULL || m_sc.target_sp.get() == curr_frame.m_sc.target_sp.get()); + assert (m_sc.module_sp.get() == NULL || curr_frame.m_sc.module_sp.get() == NULL || m_sc.module_sp.get() == curr_frame.m_sc.module_sp.get()); + assert (m_sc.comp_unit == NULL || curr_frame.m_sc.comp_unit == NULL || m_sc.comp_unit == curr_frame.m_sc.comp_unit); + assert (m_sc.function == NULL || curr_frame.m_sc.function == NULL || m_sc.function == curr_frame.m_sc.function); + m_sc = curr_frame.m_sc; + m_flags.Clear(GOT_FRAME_BASE | eSymbolContextEverything); + m_flags.Set (m_sc.GetResolvedMask()); + m_frame_base.Clear(); + m_frame_base_error.Clear(); +} + + +bool +StackFrame::HasCachedData () const +{ + if (m_variable_list_sp.get()) + return true; + if (m_variable_list_value_objects.GetSize() > 0) + return true; + if (!m_disassembly.GetString().empty()) + return true; + return false; +} + +bool +StackFrame::GetStatus (Stream& strm, + bool show_frame_info, + bool show_source) +{ + + if (show_frame_info) + { + strm.Indent(); + DumpUsingSettingsFormat (&strm); + } + + if (show_source) + { + ExecutionContext exe_ctx (shared_from_this()); + bool have_source = false; + Debugger::StopDisassemblyType disasm_display = Debugger::eStopDisassemblyTypeNever; + Target *target = exe_ctx.GetTargetPtr(); + if (target) + { + Debugger &debugger = target->GetDebugger(); + const uint32_t source_lines_before = debugger.GetStopSourceLineCount(true); + const uint32_t source_lines_after = debugger.GetStopSourceLineCount(false); + disasm_display = debugger.GetStopDisassemblyDisplay (); + + if (source_lines_before > 0 || source_lines_after > 0) + { + GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry); + + if (m_sc.comp_unit && m_sc.line_entry.IsValid()) + { + have_source = true; + target->GetSourceManager().DisplaySourceLinesWithLineNumbers (m_sc.line_entry.file, + m_sc.line_entry.line, + source_lines_before, + source_lines_after, + "->", + &strm); + } + } + switch (disasm_display) + { + case Debugger::eStopDisassemblyTypeNever: + break; + + case Debugger::eStopDisassemblyTypeNoSource: + if (have_source) + break; + // Fall through to next case + case Debugger::eStopDisassemblyTypeAlways: + if (target) + { + const uint32_t disasm_lines = debugger.GetDisassemblyLineCount(); + if (disasm_lines > 0) + { + const ArchSpec &target_arch = target->GetArchitecture(); + AddressRange pc_range; + pc_range.GetBaseAddress() = GetFrameCodeAddress(); + pc_range.SetByteSize(disasm_lines * target_arch.GetMaximumOpcodeByteSize()); + const char *plugin_name = NULL; + const char *flavor = NULL; + Disassembler::Disassemble (target->GetDebugger(), + target_arch, + plugin_name, + flavor, + exe_ctx, + pc_range, + disasm_lines, + 0, + Disassembler::eOptionMarkPCAddress, + strm); + } + } + break; + } + } + } + return true; +} + |