llvm-project/lldb/source/Symbol/Variable.cpp

979 lines
36 KiB
C++
Raw Normal View History

//===-- 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"
<rdar://problem/11757916> Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes: - Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file". - modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly - Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was. - modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile() Cleaned up header includes a bit as well. llvm-svn: 162860
2012-08-30 05:13:06 +08:00
#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/CompilerDecl.h"
#include "lldb/Symbol/CompilerDeclContext.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/Type.h"
TypeSystem is now a plugin interface and removed any "ClangASTContext &Class::GetClangASTContext()" functions. This cleans up type systems to be more pluggable. Prior to this we had issues: - Module, SymbolFile, and many others has "ClangASTContext &GetClangASTContext()" functions. All have been switched over to use "TypeSystem *GetTypeSystemForLanguage()" - Cleaned up any places that were using the GetClangASTContext() functions to use TypeSystem - Cleaned up Module so that it no longer has dedicated type system member variables: lldb::ClangASTContextUP m_ast; ///< The Clang AST context for this module. lldb::GoASTContextUP m_go_ast; ///< The Go AST context for this module. Now we have a type system map: typedef std::map<lldb::LanguageType, lldb::TypeSystemSP> TypeSystemMap; TypeSystemMap m_type_system_map; ///< A map of any type systems associated with this module - Many places in code were using ClangASTContext static functions to place with CompilerType objects and add modifiers (const, volatile, restrict) and to make typedefs, L and R value references and more. These have been made into CompilerType functions that are abstract: class CompilerType { ... //---------------------------------------------------------------------- // Return a new CompilerType that is a L value reference to this type if // this type is valid and the type system supports L value references, // else return an invalid type. //---------------------------------------------------------------------- CompilerType GetLValueReferenceType () const; //---------------------------------------------------------------------- // Return a new CompilerType that is a R value reference to this type if // this type is valid and the type system supports R value references, // else return an invalid type. //---------------------------------------------------------------------- CompilerType GetRValueReferenceType () const; //---------------------------------------------------------------------- // Return a new CompilerType adds a const modifier to this type if // this type is valid and the type system supports const modifiers, // else return an invalid type. //---------------------------------------------------------------------- CompilerType AddConstModifier () const; //---------------------------------------------------------------------- // Return a new CompilerType adds a volatile modifier to this type if // this type is valid and the type system supports volatile modifiers, // else return an invalid type. //---------------------------------------------------------------------- CompilerType AddVolatileModifier () const; //---------------------------------------------------------------------- // Return a new CompilerType adds a restrict modifier to this type if // this type is valid and the type system supports restrict modifiers, // else return an invalid type. //---------------------------------------------------------------------- CompilerType AddRestrictModifier () const; //---------------------------------------------------------------------- // Create a typedef to this type using "name" as the name of the typedef // this type is valid and the type system supports typedefs, else return // an invalid type. //---------------------------------------------------------------------- CompilerType CreateTypedef (const char *name, const CompilerDeclContext &decl_ctx) const; }; Other changes include: - Removed "CompilerType TypeSystem::GetIntTypeFromBitSize(...)" and CompilerType TypeSystem::GetFloatTypeFromBitSize(...) and replaced it with "CompilerType TypeSystem::GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, size_t bit_size);" - Fixed code in Type.h to not request the full type for a type for no good reason, just request the forward type and let the type expand as needed llvm-svn: 247953
2015-09-18 06:23:34 +08:00
#include "lldb/Symbol/TypeSystem.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
//----------------------------------------------------------------------
TypeSystem is now a plugin interface and removed any "ClangASTContext &Class::GetClangASTContext()" functions. This cleans up type systems to be more pluggable. Prior to this we had issues: - Module, SymbolFile, and many others has "ClangASTContext &GetClangASTContext()" functions. All have been switched over to use "TypeSystem *GetTypeSystemForLanguage()" - Cleaned up any places that were using the GetClangASTContext() functions to use TypeSystem - Cleaned up Module so that it no longer has dedicated type system member variables: lldb::ClangASTContextUP m_ast; ///< The Clang AST context for this module. lldb::GoASTContextUP m_go_ast; ///< The Go AST context for this module. Now we have a type system map: typedef std::map<lldb::LanguageType, lldb::TypeSystemSP> TypeSystemMap; TypeSystemMap m_type_system_map; ///< A map of any type systems associated with this module - Many places in code were using ClangASTContext static functions to place with CompilerType objects and add modifiers (const, volatile, restrict) and to make typedefs, L and R value references and more. These have been made into CompilerType functions that are abstract: class CompilerType { ... //---------------------------------------------------------------------- // Return a new CompilerType that is a L value reference to this type if // this type is valid and the type system supports L value references, // else return an invalid type. //---------------------------------------------------------------------- CompilerType GetLValueReferenceType () const; //---------------------------------------------------------------------- // Return a new CompilerType that is a R value reference to this type if // this type is valid and the type system supports R value references, // else return an invalid type. //---------------------------------------------------------------------- CompilerType GetRValueReferenceType () const; //---------------------------------------------------------------------- // Return a new CompilerType adds a const modifier to this type if // this type is valid and the type system supports const modifiers, // else return an invalid type. //---------------------------------------------------------------------- CompilerType AddConstModifier () const; //---------------------------------------------------------------------- // Return a new CompilerType adds a volatile modifier to this type if // this type is valid and the type system supports volatile modifiers, // else return an invalid type. //---------------------------------------------------------------------- CompilerType AddVolatileModifier () const; //---------------------------------------------------------------------- // Return a new CompilerType adds a restrict modifier to this type if // this type is valid and the type system supports restrict modifiers, // else return an invalid type. //---------------------------------------------------------------------- CompilerType AddRestrictModifier () const; //---------------------------------------------------------------------- // Create a typedef to this type using "name" as the name of the typedef // this type is valid and the type system supports typedefs, else return // an invalid type. //---------------------------------------------------------------------- CompilerType CreateTypedef (const char *name, const CompilerDeclContext &decl_ctx) const; }; Other changes include: - Removed "CompilerType TypeSystem::GetIntTypeFromBitSize(...)" and CompilerType TypeSystem::GetFloatTypeFromBitSize(...) and replaced it with "CompilerType TypeSystem::GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, size_t bit_size);" - Fixed code in Type.h to not request the full type for a type for no good reason, just request the forward type and let the type expand as needed llvm-svn: 247953
2015-09-18 06:23:34 +08:00
Variable::Variable (lldb::user_id_t uid,
const char *name,
const char *mangled, // The mangled or fully qualified name of the variable.
const lldb::SymbolFileTypeSP &symfile_type_sp,
ValueType scope,
SymbolContextScope *context,
const RangeList& scope_range,
TypeSystem is now a plugin interface and removed any "ClangASTContext &Class::GetClangASTContext()" functions. This cleans up type systems to be more pluggable. Prior to this we had issues: - Module, SymbolFile, and many others has "ClangASTContext &GetClangASTContext()" functions. All have been switched over to use "TypeSystem *GetTypeSystemForLanguage()" - Cleaned up any places that were using the GetClangASTContext() functions to use TypeSystem - Cleaned up Module so that it no longer has dedicated type system member variables: lldb::ClangASTContextUP m_ast; ///< The Clang AST context for this module. lldb::GoASTContextUP m_go_ast; ///< The Go AST context for this module. Now we have a type system map: typedef std::map<lldb::LanguageType, lldb::TypeSystemSP> TypeSystemMap; TypeSystemMap m_type_system_map; ///< A map of any type systems associated with this module - Many places in code were using ClangASTContext static functions to place with CompilerType objects and add modifiers (const, volatile, restrict) and to make typedefs, L and R value references and more. These have been made into CompilerType functions that are abstract: class CompilerType { ... //---------------------------------------------------------------------- // Return a new CompilerType that is a L value reference to this type if // this type is valid and the type system supports L value references, // else return an invalid type. //---------------------------------------------------------------------- CompilerType GetLValueReferenceType () const; //---------------------------------------------------------------------- // Return a new CompilerType that is a R value reference to this type if // this type is valid and the type system supports R value references, // else return an invalid type. //---------------------------------------------------------------------- CompilerType GetRValueReferenceType () const; //---------------------------------------------------------------------- // Return a new CompilerType adds a const modifier to this type if // this type is valid and the type system supports const modifiers, // else return an invalid type. //---------------------------------------------------------------------- CompilerType AddConstModifier () const; //---------------------------------------------------------------------- // Return a new CompilerType adds a volatile modifier to this type if // this type is valid and the type system supports volatile modifiers, // else return an invalid type. //---------------------------------------------------------------------- CompilerType AddVolatileModifier () const; //---------------------------------------------------------------------- // Return a new CompilerType adds a restrict modifier to this type if // this type is valid and the type system supports restrict modifiers, // else return an invalid type. //---------------------------------------------------------------------- CompilerType AddRestrictModifier () const; //---------------------------------------------------------------------- // Create a typedef to this type using "name" as the name of the typedef // this type is valid and the type system supports typedefs, else return // an invalid type. //---------------------------------------------------------------------- CompilerType CreateTypedef (const char *name, const CompilerDeclContext &decl_ctx) const; }; Other changes include: - Removed "CompilerType TypeSystem::GetIntTypeFromBitSize(...)" and CompilerType TypeSystem::GetFloatTypeFromBitSize(...) and replaced it with "CompilerType TypeSystem::GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, size_t bit_size);" - Fixed code in Type.h to not request the full type for a type for no good reason, just request the forward type and let the type expand as needed llvm-svn: 247953
2015-09-18 06:23:34 +08:00
Declaration* decl_ptr,
const DWARFExpression& location,
bool external,
bool artificial,
bool static_member) :
UserID(uid),
m_name(name),
m_mangled (ConstString(mangled)),
Added a new class called lldb_private::SymbolFileType which is designed to take a SymbolFile reference and a lldb::user_id_t and be used in objects which represent things in debug symbols that have types where we don't need to know the true type yet, such as in lldb_private::Variable objects. This allows us to defer resolving the type until something is used. More specifically this allows us to get 1000 local variables from the current function, and if the user types "frame variable argc", we end up _only_ resolving the type for "argc" and not for the 999 other local variables. We can expand the use of this as needed in the future. Modified the DWARFMappedHash class to be able to read the HashData that has more than just the DIE offset. It currently will read the atoms in the header definition and read the data correctly. Currently only the DIE offset and type flags are supported. This is needed for adding type flags to the .apple_types hash accelerator tables. Fixed a assertion crash that would happen if we have a variable that had a DW_AT_const_value instead of a location where "location.LocationContains_DW_OP_addr()" would end up asserting when it tried to parse the variable location as a DWARF opcode list. Decreased the amount of memory that LLDB would use when evaluating an expression by 3x - 4x for clang. There was a place in the namespace lookup code that was parsing all namespaces with a certain name in a DWARF file instead of stopping when it found the first match. This was causing all of the compile units with a matching namespace to get parsed into memory and causing unnecessary memory bloat. Improved "Target::EvaluateExpression(...)" to not try and find a variable when the expression contains characters that would certainly cause an expression to need to be evaluated by the debugger. llvm-svn: 146130
2011-12-08 10:13:16 +08:00
m_symfile_type_sp(symfile_type_sp),
m_scope(scope),
m_owner_scope(context),
m_scope_range(scope_range),
m_declaration(decl_ptr),
m_location(location),
m_external(external),
m_artificial(artificial),
m_static_member(static_member)
{
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
Variable::~Variable()
{
}
lldb::LanguageType
Variable::GetLanguage () const
{
SymbolContext variable_sc;
m_owner_scope->CalculateSymbolContext(&variable_sc);
if (variable_sc.comp_unit)
return variable_sc.comp_unit->GetLanguage();
return lldb::eLanguageTypeUnknown;
}
ConstString
Variable::GetName() const
{
ConstString name = m_mangled.GetName(GetLanguage());
if (name)
return name;
return m_name;
}
ConstString
Variable::GetUnqualifiedName() const
{
return m_name;
}
bool
Variable::NameMatches (const ConstString &name) const
{
if (m_name == name)
return true;
SymbolContext variable_sc;
m_owner_scope->CalculateSymbolContext(&variable_sc);
LanguageType language = eLanguageTypeUnknown;
if (variable_sc.comp_unit)
language = variable_sc.comp_unit->GetLanguage();
return m_mangled.NameMatches (name, language);
}
bool
Variable::NameMatches (const RegularExpression& regex) const
{
if (regex.Execute (m_name.AsCString()))
return true;
if (m_mangled)
return m_mangled.NameMatches (regex, GetLanguage());
return false;
}
Added a new class called lldb_private::SymbolFileType which is designed to take a SymbolFile reference and a lldb::user_id_t and be used in objects which represent things in debug symbols that have types where we don't need to know the true type yet, such as in lldb_private::Variable objects. This allows us to defer resolving the type until something is used. More specifically this allows us to get 1000 local variables from the current function, and if the user types "frame variable argc", we end up _only_ resolving the type for "argc" and not for the 999 other local variables. We can expand the use of this as needed in the future. Modified the DWARFMappedHash class to be able to read the HashData that has more than just the DIE offset. It currently will read the atoms in the header definition and read the data correctly. Currently only the DIE offset and type flags are supported. This is needed for adding type flags to the .apple_types hash accelerator tables. Fixed a assertion crash that would happen if we have a variable that had a DW_AT_const_value instead of a location where "location.LocationContains_DW_OP_addr()" would end up asserting when it tried to parse the variable location as a DWARF opcode list. Decreased the amount of memory that LLDB would use when evaluating an expression by 3x - 4x for clang. There was a place in the namespace lookup code that was parsing all namespaces with a certain name in a DWARF file instead of stopping when it found the first match. This was causing all of the compile units with a matching namespace to get parsed into memory and causing unnecessary memory bloat. Improved "Target::EvaluateExpression(...)" to not try and find a variable when the expression contains characters that would certainly cause an expression to need to be evaluated by the debugger. llvm-svn: 146130
2011-12-08 10:13:16 +08:00
Type *
Variable::GetType()
{
if (m_symfile_type_sp)
return m_symfile_type_sp->GetType();
return nullptr;
Added a new class called lldb_private::SymbolFileType which is designed to take a SymbolFile reference and a lldb::user_id_t and be used in objects which represent things in debug symbols that have types where we don't need to know the true type yet, such as in lldb_private::Variable objects. This allows us to defer resolving the type until something is used. More specifically this allows us to get 1000 local variables from the current function, and if the user types "frame variable argc", we end up _only_ resolving the type for "argc" and not for the 999 other local variables. We can expand the use of this as needed in the future. Modified the DWARFMappedHash class to be able to read the HashData that has more than just the DIE offset. It currently will read the atoms in the header definition and read the data correctly. Currently only the DIE offset and type flags are supported. This is needed for adding type flags to the .apple_types hash accelerator tables. Fixed a assertion crash that would happen if we have a variable that had a DW_AT_const_value instead of a location where "location.LocationContains_DW_OP_addr()" would end up asserting when it tried to parse the variable location as a DWARF opcode list. Decreased the amount of memory that LLDB would use when evaluating an expression by 3x - 4x for clang. There was a place in the namespace lookup code that was parsing all namespaces with a certain name in a DWARF file instead of stopping when it found the first match. This was causing all of the compile units with a matching namespace to get parsed into memory and causing unnecessary memory bloat. Improved "Target::EvaluateExpression(...)" to not try and find a variable when the expression contains characters that would certainly cause an expression to need to be evaluated by the debugger. llvm-svn: 146130
2011-12-08 10:13:16 +08:00
}
void
Variable::Dump(Stream *s, bool show_context) const
{
s->Printf("%p: ", static_cast<const void*>(this));
s->Indent();
*s << "Variable" << (const UserID&)*this;
if (m_name)
*s << ", name = \"" << m_name << "\"";
Added a new class called lldb_private::SymbolFileType which is designed to take a SymbolFile reference and a lldb::user_id_t and be used in objects which represent things in debug symbols that have types where we don't need to know the true type yet, such as in lldb_private::Variable objects. This allows us to defer resolving the type until something is used. More specifically this allows us to get 1000 local variables from the current function, and if the user types "frame variable argc", we end up _only_ resolving the type for "argc" and not for the 999 other local variables. We can expand the use of this as needed in the future. Modified the DWARFMappedHash class to be able to read the HashData that has more than just the DIE offset. It currently will read the atoms in the header definition and read the data correctly. Currently only the DIE offset and type flags are supported. This is needed for adding type flags to the .apple_types hash accelerator tables. Fixed a assertion crash that would happen if we have a variable that had a DW_AT_const_value instead of a location where "location.LocationContains_DW_OP_addr()" would end up asserting when it tried to parse the variable location as a DWARF opcode list. Decreased the amount of memory that LLDB would use when evaluating an expression by 3x - 4x for clang. There was a place in the namespace lookup code that was parsing all namespaces with a certain name in a DWARF file instead of stopping when it found the first match. This was causing all of the compile units with a matching namespace to get parsed into memory and causing unnecessary memory bloat. Improved "Target::EvaluateExpression(...)" to not try and find a variable when the expression contains characters that would certainly cause an expression to need to be evaluated by the debugger. llvm-svn: 146130
2011-12-08 10:13:16 +08:00
if (m_symfile_type_sp)
{
Added a new class called lldb_private::SymbolFileType which is designed to take a SymbolFile reference and a lldb::user_id_t and be used in objects which represent things in debug symbols that have types where we don't need to know the true type yet, such as in lldb_private::Variable objects. This allows us to defer resolving the type until something is used. More specifically this allows us to get 1000 local variables from the current function, and if the user types "frame variable argc", we end up _only_ resolving the type for "argc" and not for the 999 other local variables. We can expand the use of this as needed in the future. Modified the DWARFMappedHash class to be able to read the HashData that has more than just the DIE offset. It currently will read the atoms in the header definition and read the data correctly. Currently only the DIE offset and type flags are supported. This is needed for adding type flags to the .apple_types hash accelerator tables. Fixed a assertion crash that would happen if we have a variable that had a DW_AT_const_value instead of a location where "location.LocationContains_DW_OP_addr()" would end up asserting when it tried to parse the variable location as a DWARF opcode list. Decreased the amount of memory that LLDB would use when evaluating an expression by 3x - 4x for clang. There was a place in the namespace lookup code that was parsing all namespaces with a certain name in a DWARF file instead of stopping when it found the first match. This was causing all of the compile units with a matching namespace to get parsed into memory and causing unnecessary memory bloat. Improved "Target::EvaluateExpression(...)" to not try and find a variable when the expression contains characters that would certainly cause an expression to need to be evaluated by the debugger. llvm-svn: 146130
2011-12-08 10:13:16 +08:00
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 != nullptr)
{
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 = ");
Looking at some of the test suite failures in DWARF in .o files with the debug map showed that the location lists in the .o files needed some refactoring in order to work. The case that was failing was where a function that was in the "__TEXT.__textcoal_nt" in the .o file, and in the "__TEXT.__text" section in the main executable. This made symbol lookup fail due to the way we were finding a real address in the debug map which was by finding the section that the function was in in the .o file and trying to find this in the main executable. Now the section list supports finding a linked address in a section or any child sections. After fixing this, we ran into issue that were due to DWARF and how it represents locations lists. DWARF makes a list of address ranges and expressions that go along with those address ranges. The location addresses are expressed in terms of a compile unit address + offset. This works fine as long as nothing moves around. When stuff moves around and offsets change between the remapped compile unit base address and the new function address, then we can run into trouble. To deal with this, we now store supply a location list slide amount to any location list expressions that will allow us to make the location list addresses into zero based offsets from the object that owns the location list (always a function in our case). With these fixes we can now re-link random address ranges inside the debugger for use with our DWARF + debug map, incremental linking, and more. Another issue that arose when doing the DWARF in the .o files was that GCC 4.2 emits a ".debug_aranges" that only mentions functions that are externally visible. This makes .debug_aranges useless to us and we now generate a real address range lookup table in the DWARF parser at the same time as we index the name tables (that are needed because .debug_pubnames is just as useless). llvm-gcc doesn't generate a .debug_aranges section, though this could be fixed, we aren't going to rely upon it. Renamed a bunch of "UINT_MAX" to "UINT32_MAX". llvm-svn: 113829
2010-09-14 10:20:48 +08:00
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 = nullptr;
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 = nullptr;
sc.line_entry.Clear();
bool show_inlined_frames = false;
const bool show_function_arguments = true;
const bool show_function_name = true;
dumped_declaration_info = sc.DumpStopContext (s,
nullptr,
Address(),
show_fullpaths,
show_module,
show_inlined_frames,
show_function_arguments,
show_function_name);
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);
}
CompilerDeclContext
Variable::GetDeclContext ()
{
Type *type = GetType();
if (type)
return type->GetSymbolFile()->GetDeclContextContainingUID(GetID());
return CompilerDeclContext();
}
CompilerDecl
Variable::GetDecl ()
{
Type *type = GetType();
return type ? type->GetSymbolFile()->GetDeclForUID(GetID()) : CompilerDecl();
}
void
Variable::CalculateSymbolContext (SymbolContext *sc)
{
if (m_owner_scope)
{
m_owner_scope->CalculateSymbolContext(sc);
sc->variable = this;
}
else
sc->Clear(false);
}
bool
Variable::LocationIsValidForFrame (StackFrame *frame)
{
2011-05-30 08:49:24 +08:00
// Is the variable is described by a single location?
if (!m_location.IsLocationList())
{
2011-05-30 08:49:24 +08:00
// Yes it is, the location is valid.
return true;
2011-05-30 08:49:24 +08:00
}
2011-05-30 08:49:24 +08:00
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());
Looking at some of the test suite failures in DWARF in .o files with the debug map showed that the location lists in the .o files needed some refactoring in order to work. The case that was failing was where a function that was in the "__TEXT.__textcoal_nt" in the .o file, and in the "__TEXT.__text" section in the main executable. This made symbol lookup fail due to the way we were finding a real address in the debug map which was by finding the section that the function was in in the .o file and trying to find this in the main executable. Now the section list supports finding a linked address in a section or any child sections. After fixing this, we ran into issue that were due to DWARF and how it represents locations lists. DWARF makes a list of address ranges and expressions that go along with those address ranges. The location addresses are expressed in terms of a compile unit address + offset. This works fine as long as nothing moves around. When stuff moves around and offsets change between the remapped compile unit base address and the new function address, then we can run into trouble. To deal with this, we now store supply a location list slide amount to any location list expressions that will allow us to make the location list addresses into zero based offsets from the object that owns the location list (always a function in our case). With these fixes we can now re-link random address ranges inside the debugger for use with our DWARF + debug map, incremental linking, and more. Another issue that arose when doing the DWARF in the .o files was that GCC 4.2 emits a ".debug_aranges" that only mentions functions that are externally visible. This makes .debug_aranges useless to us and we now generate a real address range lookup table in the DWARF parser at the same time as we index the name tables (that are needed because .debug_pubnames is just as useless). llvm-gcc doesn't generate a .debug_aranges section, though this could be fixed, we aren't going to rely upon it. Renamed a bunch of "UINT_MAX" to "UINT32_MAX". llvm-svn: 113829
2010-09-14 10:20:48 +08:00
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
2011-05-30 08:49:24 +08:00
return m_location.LocationListContainsAddress (loclist_base_load_addr,
frame->GetFrameCodeAddress().GetLoadAddress (target_sp.get()));
}
2011-05-30 08:49:24 +08:00
}
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;
}
2011-05-30 08:49:24 +08:00
bool
Variable::IsInScope (StackFrame *frame)
2011-05-30 08:49:24 +08:00
{
switch (m_scope)
{
case eValueTypeRegister:
case eValueTypeRegisterSet:
return frame != nullptr;
2011-05-30 08:49:24 +08:00
case eValueTypeConstResult:
case eValueTypeVariableGlobal:
case eValueTypeVariableStatic:
return true;
2011-05-30 08:49:24 +08:00
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);
2011-05-30 08:49:24 +08:00
// Check for static or global variable defined at the compile unit
// level that wasn't defined in a block
if (variable_sc.block == nullptr)
return true;
2011-05-30 08:49:24 +08:00
// Check if the variable is valid in the current block
if (variable_sc.block != deepest_frame_block &&
!variable_sc.block->Contains(deepest_frame_block))
return false;
// If no scope range is specified then it means that the scope is the same as the
// scope of the enclosing lexical block.
if (m_scope_range.IsEmpty())
Looking at some of the test suite failures in DWARF in .o files with the debug map showed that the location lists in the .o files needed some refactoring in order to work. The case that was failing was where a function that was in the "__TEXT.__textcoal_nt" in the .o file, and in the "__TEXT.__text" section in the main executable. This made symbol lookup fail due to the way we were finding a real address in the debug map which was by finding the section that the function was in in the .o file and trying to find this in the main executable. Now the section list supports finding a linked address in a section or any child sections. After fixing this, we ran into issue that were due to DWARF and how it represents locations lists. DWARF makes a list of address ranges and expressions that go along with those address ranges. The location addresses are expressed in terms of a compile unit address + offset. This works fine as long as nothing moves around. When stuff moves around and offsets change between the remapped compile unit base address and the new function address, then we can run into trouble. To deal with this, we now store supply a location list slide amount to any location list expressions that will allow us to make the location list addresses into zero based offsets from the object that owns the location list (always a function in our case). With these fixes we can now re-link random address ranges inside the debugger for use with our DWARF + debug map, incremental linking, and more. Another issue that arose when doing the DWARF in the .o files was that GCC 4.2 emits a ".debug_aranges" that only mentions functions that are externally visible. This makes .debug_aranges useless to us and we now generate a real address range lookup table in the DWARF parser at the same time as we index the name tables (that are needed because .debug_pubnames is just as useless). llvm-gcc doesn't generate a .debug_aranges section, though this could be fixed, we aren't going to rely upon it. Renamed a bunch of "UINT_MAX" to "UINT32_MAX". llvm-svn: 113829
2010-09-14 10:20:48 +08:00
return true;
addr_t file_address = frame->GetFrameCodeAddress().GetFileAddress();
return m_scope_range.FindEntryThatContains(file_address) != nullptr;
}
}
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, &regex_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 = nullptr;
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 = nullptr;
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 CompilerType& compiler_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 CompilerType& compiler_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 CompilerType& compiler_type,
StringList &matches,
bool &word_complete)
{
// We are in a type parsing child members
const uint32_t num_bases = compiler_type.GetNumDirectBaseClasses();
if (num_bases > 0)
{
for (uint32_t i = 0; i < num_bases; ++i)
{
CompilerType base_class_type = compiler_type.GetDirectBaseClassAtIndex(i, nullptr);
PrivateAutoCompleteMembers (frame,
partial_member_name,
partial_path,
prefix_path,
base_class_type.GetCanonicalType(),
matches,
word_complete);
}
}
const uint32_t num_vbases = compiler_type.GetNumVirtualBaseClasses();
if (num_vbases > 0)
{
for (uint32_t i = 0; i < num_vbases; ++i)
{
CompilerType vbase_class_type = compiler_type.GetVirtualBaseClassAtIndex(i,nullptr);
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 = compiler_type.GetNumFields();
if (num_fields > 0)
{
for (uint32_t i = 0; i < num_fields; ++i)
{
std::string member_name;
CompilerType member_compiler_type = compiler_type.GetFieldAtIndex (i, member_name, nullptr, nullptr, nullptr);
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_compiler_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 CompilerType& compiler_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 = compiler_type.GetTypeClass();
if (partial_path.empty())
{
if (compiler_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 (compiler_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);
if (variable_list)
{
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("*"),
compiler_type,
matches,
word_complete);
}
break;
case '&':
if (prefix_path.empty())
{
PrivateAutoComplete (frame,
partial_path.substr(1),
std::string("&"),
compiler_type,
matches,
word_complete);
}
break;
case '-':
if (partial_path[1] == '>' && !prefix_path.empty())
{
switch (type_class)
{
case lldb::eTypeClassPointer:
{
CompilerType pointee_type(compiler_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);
}
}
break;
default:
break;
}
}
break;
case '.':
if (compiler_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 + ".",
compiler_type,
matches,
word_complete);
}
else
{
// Nothing after the ".", so list all members
PrivateAutoCompleteMembers (frame,
std::string(),
partial_path,
prefix_path + ".",
compiler_type,
matches,
word_complete);
}
break;
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 (compiler_type.IsValid())
{
PrivateAutoCompleteMembers (frame,
token,
remaining_partial_path,
prefix_path,
compiler_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);
if (!variable_list)
break;
const size_t num_variables = variable_list->GetSize();
for (size_t i=0; i<num_variables; ++i)
{
Variable *variable = variable_list->GetVariableAtIndex(i).get();
if (!variable)
continue;
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)
{
CompilerType variable_compiler_type (variable_type->GetForwardCompilerType ());
PrivateAutoComplete (frame,
remaining_partial_path,
prefix_path + token, // Anything that has been resolved already will be in here
variable_compiler_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;
CompilerType compiler_type;
if (partial_path_cstr && partial_path_cstr[0])
partial_path = partial_path_cstr;
PrivateAutoComplete (exe_ctx.GetFramePtr(),
partial_path,
prefix_path,
compiler_type,
matches,
word_complete);
return matches.GetSize();
}