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

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

740 lines
24 KiB
C++
Raw Normal View History

//===-- Variable.cpp ------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#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/ValueObject.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/CompilerDecl.h"
#include "lldb/Symbol/CompilerDeclContext.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/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/Stream.h"
#include "llvm/ADT/Twine.h"
using namespace lldb;
using namespace lldb_private;
2019-09-21 01:15:57 +08:00
Variable::Variable(lldb::user_id_t uid, const char *name, const char *mangled,
const lldb::SymbolFileTypeSP &symfile_type_sp,
ValueType scope, SymbolContextScope *context,
const RangeList &scope_range, Declaration *decl_ptr,
const DWARFExpression &location, bool external,
bool artificial, bool location_is_constant_data,
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_loc_is_const_data(location_is_constant_data),
m_static_member(static_member) {}
Variable::~Variable() {}
lldb::LanguageType Variable::GetLanguage() const {
lldb::LanguageType lang = m_mangled.GuessLanguage();
if (lang != lldb::eLanguageTypeUnknown)
return lang;
if (auto *func = m_owner_scope->CalculateSymbolContextFunction()) {
if ((lang = func->GetLanguage()) != lldb::eLanguageTypeUnknown)
return lang;
} else if (auto *comp_unit =
m_owner_scope->CalculateSymbolContextCompileUnit()) {
if ((lang = comp_unit->GetLanguage()) != lldb::eLanguageTypeUnknown)
return lang;
}
return lldb::eLanguageTypeUnknown;
}
ConstString Variable::GetName() const {
ConstString name = m_mangled.GetName();
if (name)
return name;
return m_name;
}
ConstString Variable::GetUnqualifiedName() const { return m_name; }
bool Variable::NameMatches(ConstString name) const {
if (m_name == name)
return true;
SymbolContext variable_sc;
m_owner_scope->CalculateSymbolContext(&variable_sc);
return m_mangled.NameMatches(name);
}
bool Variable::NameMatches(const RegularExpression &regex) const {
if (regex.Execute(m_name.AsCString()))
return true;
if (m_mangled)
return m_mangled.NameMatches(regex);
return false;
}
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));
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
s->Indent();
*s << "Variable" << (const UserID &)*this;
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_name)
*s << ", name = \"" << m_name << "\"";
if (m_symfile_type_sp) {
Type *type = m_symfile_type_sp->GetType();
Added support for thread local variables on all Apple OS variants. We had support that assumed that thread local data for a variable could be determined solely from the module in which the variable exists. While this work for linux, it doesn't work for Apple OSs. The DWARF for thread local variables consists of location opcodes that do something like: DW_OP_const8u (x) DW_OP_form_tls_address or DW_OP_const8u (x) DW_OP_GNU_push_tls_address The "x" is allowed to be anything that is needed to determine the location of the variable. For Linux "x" is the offset within the TLS data for a given executable (ModuleSP in LLDB). For Apple OS variants, it is the file address of the data structure that contains a pthread key that can be used with pthread_getspecific() and the offset needed. This fix passes the "x" along to the thread: virtual lldb::addr_t lldb_private::Thread::GetThreadLocalData(const lldb::ModuleSP module, lldb::addr_t tls_file_addr); Then this is passed along to the DynamicLoader::GetThreadLocalData(): virtual lldb::addr_t lldb_private::DynamicLoader::GetThreadLocalData(const lldb::ModuleSP module, const lldb::ThreadSP thread, lldb::addr_t tls_file_addr); This allows each DynamicLoader plug-in do the right thing for the current OS. The DynamicLoaderMacOSXDYLD was modified to be able to grab the pthread key from the data structure that is in memory and call "void *pthread_getspecific(pthread_key_t key)" to get the value of the thread local storage and it caches it per thread since it never changes. I had to update the test case to access the thread local data before trying to print it as on Apple OS variants, thread locals are not available unless they have been accessed at least one by the current thread. I also added a new lldb::ValueType named "eValueTypeVariableThreadLocal" so that we can ask SBValue objects for their ValueType and be able to tell when we have a thread local variable. <rdar://problem/23308080> llvm-svn: 274366
2016-07-02 01:17:23 +08:00
if (type) {
s->Format(", type = {{{0:x-16}} {1} (", type->GetID(), type);
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->DumpTypeName(s);
s->PutChar(')');
}
}
if (m_scope != eValueTypeInvalid) {
s->PutCString(", scope = ");
switch (m_scope) {
2011-05-30 08:49:24 +08:00
case eValueTypeVariableGlobal:
s->PutCString(m_external ? "global" : "static");
break;
case eValueTypeVariableArgument:
Added support for thread local variables on all Apple OS variants. We had support that assumed that thread local data for a variable could be determined solely from the module in which the variable exists. While this work for linux, it doesn't work for Apple OSs. The DWARF for thread local variables consists of location opcodes that do something like: DW_OP_const8u (x) DW_OP_form_tls_address or DW_OP_const8u (x) DW_OP_GNU_push_tls_address The "x" is allowed to be anything that is needed to determine the location of the variable. For Linux "x" is the offset within the TLS data for a given executable (ModuleSP in LLDB). For Apple OS variants, it is the file address of the data structure that contains a pthread key that can be used with pthread_getspecific() and the offset needed. This fix passes the "x" along to the thread: virtual lldb::addr_t lldb_private::Thread::GetThreadLocalData(const lldb::ModuleSP module, lldb::addr_t tls_file_addr); Then this is passed along to the DynamicLoader::GetThreadLocalData(): virtual lldb::addr_t lldb_private::DynamicLoader::GetThreadLocalData(const lldb::ModuleSP module, const lldb::ThreadSP thread, lldb::addr_t tls_file_addr); This allows each DynamicLoader plug-in do the right thing for the current OS. The DynamicLoaderMacOSXDYLD was modified to be able to grab the pthread key from the data structure that is in memory and call "void *pthread_getspecific(pthread_key_t key)" to get the value of the thread local storage and it caches it per thread since it never changes. I had to update the test case to access the thread local data before trying to print it as on Apple OS variants, thread locals are not available unless they have been accessed at least one by the current thread. I also added a new lldb::ValueType named "eValueTypeVariableThreadLocal" so that we can ask SBValue objects for their ValueType and be able to tell when we have a thread local variable. <rdar://problem/23308080> llvm-svn: 274366
2016-07-02 01:17:23 +08:00
s->PutCString("parameter");
break;
case eValueTypeVariableLocal:
s->PutCString("local");
break;
Added support for thread local variables on all Apple OS variants. We had support that assumed that thread local data for a variable could be determined solely from the module in which the variable exists. While this work for linux, it doesn't work for Apple OSs. The DWARF for thread local variables consists of location opcodes that do something like: DW_OP_const8u (x) DW_OP_form_tls_address or DW_OP_const8u (x) DW_OP_GNU_push_tls_address The "x" is allowed to be anything that is needed to determine the location of the variable. For Linux "x" is the offset within the TLS data for a given executable (ModuleSP in LLDB). For Apple OS variants, it is the file address of the data structure that contains a pthread key that can be used with pthread_getspecific() and the offset needed. This fix passes the "x" along to the thread: virtual lldb::addr_t lldb_private::Thread::GetThreadLocalData(const lldb::ModuleSP module, lldb::addr_t tls_file_addr); Then this is passed along to the DynamicLoader::GetThreadLocalData(): virtual lldb::addr_t lldb_private::DynamicLoader::GetThreadLocalData(const lldb::ModuleSP module, const lldb::ThreadSP thread, lldb::addr_t tls_file_addr); This allows each DynamicLoader plug-in do the right thing for the current OS. The DynamicLoaderMacOSXDYLD was modified to be able to grab the pthread key from the data structure that is in memory and call "void *pthread_getspecific(pthread_key_t key)" to get the value of the thread local storage and it caches it per thread since it never changes. I had to update the test case to access the thread local data before trying to print it as on Apple OS variants, thread locals are not available unless they have been accessed at least one by the current thread. I also added a new lldb::ValueType named "eValueTypeVariableThreadLocal" so that we can ask SBValue objects for their ValueType and be able to tell when we have a thread local variable. <rdar://problem/23308080> llvm-svn: 274366
2016-07-02 01:17:23 +08:00
case eValueTypeVariableThreadLocal:
s->PutCString("thread local");
break;
default:
s->AsRawOstream() << "??? (" << 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();
}
ABISP abi;
if (m_owner_scope) {
ModuleSP module_sp(m_owner_scope->CalculateSymbolContextModule());
if (module_sp)
abi = ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture());
}
m_location.GetDescription(s, lldb::eDescriptionLevelBrief,
loclist_base_addr, abi.get());
}
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) {
// Is the variable is described by a single location?
if (!m_location.IsLocationList()) {
// Yes it is, the location is valid.
return true;
}
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
return m_location.LocationListContainsAddress(
loclist_base_load_addr,
frame->GetFrameCodeAddress().GetLoadAddress(target_sp.get()));
}
}
return false;
}
bool Variable::LocationIsValidForAddress(const Address &address) {
// Be sure to resolve the address to section offset prior to calling this
// function.
if (address.IsSectionOffset()) {
SymbolContext sc;
CalculateSymbolContext(&sc);
if (sc.module_sp == address.GetModule()) {
2011-05-30 08:49:24 +08:00
// 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)
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 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());
}
2011-05-30 08:49:24 +08:00
}
}
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 false;
2011-05-30 08:49:24 +08:00
}
bool Variable::IsInScope(StackFrame *frame) {
switch (m_scope) {
case eValueTypeRegister:
2011-05-30 08:49:24 +08:00
case eValueTypeRegisterSet:
return frame != nullptr;
case eValueTypeConstResult:
2011-05-30 08:49:24 +08:00
case eValueTypeVariableGlobal:
case eValueTypeVariableStatic:
case eValueTypeVariableThreadLocal:
return true;
case eValueTypeVariableArgument:
2011-05-30 08:49:24 +08:00
case eValueTypeVariableLocal:
if (frame) {
// We don't have a location list, we just need to see if the block that
// this variable was defined in is currently
Block *deepest_frame_block =
frame->GetSymbolContext(eSymbolContextBlock).block;
if (deepest_frame_block) {
SymbolContext variable_sc;
CalculateSymbolContext(&variable_sc);
// Check for static or global variable defined at the compile unit
// level that wasn't defined in a block
if (variable_sc.block == nullptr)
return true;
// 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())
return true;
addr_t file_address = frame->GetFrameCodeAddress().GetFileAddress();
return m_scope_range.FindEntryThatContains(file_address) != nullptr;
}
}
break;
default:
break;
}
return false;
}
Status Variable::GetValuesForVariableExpressionPath(
llvm::StringRef variable_expr_path, ExecutionContextScope *scope,
GetVariableCallback callback, void *baton, VariableList &variable_list,
ValueObjectList &valobj_list) {
Status error;
if (!callback || variable_expr_path.empty()) {
error.SetErrorString("unknown error");
return error;
}
switch (variable_expr_path.front()) {
case '*':
error = Variable::GetValuesForVariableExpressionPath(
variable_expr_path.drop_front(), scope, callback, baton, variable_list,
valobj_list);
if (error.Fail()) {
error.SetErrorString("unknown error");
return error;
}
for (uint32_t i = 0; i < valobj_list.GetSize();) {
Status 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;
}
}
return error;
case '&': {
error = Variable::GetValuesForVariableExpressionPath(
variable_expr_path.drop_front(), scope, callback, baton, variable_list,
valobj_list);
if (error.Success()) {
for (uint32_t i = 0; i < valobj_list.GetSize();) {
Status 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(
llvm::StringRef("^([A-Za-z_:][A-Za-z_0-9:]*)(.*)"));
llvm::SmallVector<llvm::StringRef, 2> matches;
variable_list.Clear();
if (!g_regex.Execute(variable_expr_path, &matches)) {
error.SetErrorStringWithFormat(
"unable to extract a variable name from '%s'",
variable_expr_path.str().c_str());
return error;
}
std::string variable_name = matches[1].str();
if (!callback(baton, variable_name.c_str(), variable_list)) {
error.SetErrorString("unknown error");
return error;
}
uint32_t i = 0;
while (i < variable_list.GetSize()) {
VariableSP var_sp(variable_list.GetVariableAtIndex(i));
ValueObjectSP valobj_sp;
if (!var_sp) {
variable_list.RemoveVariableAtIndex(i);
continue;
}
ValueObjectSP variable_valobj_sp(
ValueObjectVariable::Create(scope, var_sp));
if (!variable_valobj_sp) {
variable_list.RemoveVariableAtIndex(i);
continue;
}
llvm::StringRef variable_sub_expr_path =
variable_expr_path.drop_front(variable_name.size());
if (!variable_sub_expr_path.empty()) {
valobj_sp = variable_valobj_sp->GetValueForExpressionPath(
variable_sub_expr_path);
if (!valobj_sp) {
error.SetErrorStringWithFormat(
"invalid expression path '%s' for variable '%s'",
variable_sub_expr_path.str().c_str(),
var_sp->GetName().GetCString());
variable_list.RemoveVariableAtIndex(i);
continue;
}
} else {
// Just the name of a variable with no extras
valobj_sp = variable_valobj_sp;
}
valobj_list.Append(valobj_sp);
++i;
}
if (variable_list.GetSize() > 0) {
error.Clear();
return error;
}
} 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()) {
ABISP abi;
if (m_owner_scope) {
ModuleSP module_sp(m_owner_scope->CalculateSymbolContextModule());
if (module_sp)
abi = ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture());
}
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.get());
}
}
return m_location.DumpLocationForAddress(s, eDescriptionLevelBrief,
LLDB_INVALID_ADDRESS, file_addr,
abi.get());
}
}
return false;
}
static void PrivateAutoComplete(
StackFrame *frame, llvm::StringRef partial_path,
const llvm::Twine
&prefix_path, // Anything that has been resolved already will be in here
const CompilerType &compiler_type, CompletionRequest &request);
static void PrivateAutoCompleteMembers(
StackFrame *frame, const std::string &partial_member_name,
llvm::StringRef partial_path,
const llvm::Twine
&prefix_path, // Anything that has been resolved already will be in here
const CompilerType &compiler_type, CompletionRequest &request) {
// 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(), request);
}
}
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(), request);
}
}
// 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() ||
llvm::StringRef(member_name).startswith(partial_member_name)) {
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(), request);
} else {
request.AddCompletion((prefix_path + member_name).str());
}
}
}
}
}
static void PrivateAutoComplete(
StackFrame *frame, llvm::StringRef partial_path,
const llvm::Twine
&prefix_path, // Anything that has been resolved already will be in here
const CompilerType &compiler_type, CompletionRequest &request) {
// 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: {
request.AddCompletion(prefix_path.str());
} break;
case eTypeClassClass:
case eTypeClassStruct:
case eTypeClassUnion:
if (prefix_path.str().back() != '.')
request.AddCompletion((prefix_path + ".").str());
break;
case eTypeClassObjCObject:
case eTypeClassObjCInterface:
break;
case eTypeClassObjCObjectPointer:
case eTypeClassPointer: {
bool omit_empty_base_classes = true;
if (compiler_type.GetNumChildren(omit_empty_base_classes, nullptr) > 0)
request.AddCompletion((prefix_path + "->").str());
else {
request.AddCompletion(prefix_path.str());
}
} break;
}
} else {
if (frame) {
const bool get_file_globals = true;
VariableList *variable_list = frame->GetVariableList(get_file_globals);
if (variable_list) {
for (const VariableSP &var_sp : *variable_list)
request.AddCompletion(var_sp->GetName().AsCString());
}
}
}
} else {
const char ch = partial_path[0];
switch (ch) {
case '*':
if (prefix_path.str().empty()) {
PrivateAutoComplete(frame, partial_path.substr(1), "*", compiler_type,
request);
}
break;
case '&':
if (prefix_path.isTriviallyEmpty()) {
PrivateAutoComplete(frame, partial_path.substr(1), std::string("&"),
compiler_type, request);
}
break;
case '-':
if (partial_path.size() > 1 && partial_path[1] == '>' &&
!prefix_path.str().empty()) {
switch (type_class) {
case lldb::eTypeClassPointer: {
CompilerType pointee_type(compiler_type.GetPointeeType());
if (partial_path.size() > 2 && partial_path[2]) {
// If there is more after the "->", then search deeper
PrivateAutoComplete(frame, partial_path.substr(2),
prefix_path + "->",
pointee_type.GetCanonicalType(), request);
} else {
// Nothing after the "->", so list all members
PrivateAutoCompleteMembers(
frame, std::string(), std::string(), prefix_path + "->",
pointee_type.GetCanonicalType(), request);
}
} break;
default:
break;
}
}
break;
case '.':
if (compiler_type.IsValid()) {
switch (type_class) {
case lldb::eTypeClassUnion:
case lldb::eTypeClassStruct:
case lldb::eTypeClassClass:
if (partial_path.size() > 1 && partial_path[1]) {
// If there is more after the ".", then search deeper
PrivateAutoComplete(frame, partial_path.substr(1),
prefix_path + ".", compiler_type, request);
} else {
// Nothing after the ".", so list all members
PrivateAutoCompleteMembers(frame, std::string(), partial_path,
prefix_path + ".", compiler_type,
request);
}
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(std::string(partial_path), 0, pos);
remaining_partial_path = std::string(partial_path.substr(pos));
if (compiler_type.IsValid()) {
PrivateAutoCompleteMembers(frame, token, remaining_partial_path,
prefix_path, compiler_type, request);
} 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;
for (VariableSP var_sp : *variable_list) {
if (!var_sp)
continue;
llvm::StringRef variable_name = var_sp->GetName().GetStringRef();
if (variable_name.startswith(token)) {
if (variable_name == token) {
Type *variable_type = var_sp->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(), request);
} else {
request.AddCompletion((prefix_path + variable_name).str());
}
} else if (remaining_partial_path.empty()) {
request.AddCompletion((prefix_path + variable_name).str());
}
}
}
}
}
break;
}
}
}
[lldb][NFC] Remove WordComplete mode, make result array indexed from 0 and remove any undocumented/redundant return values Summary: We still have some leftovers of the old completion API in the internals of LLDB that haven't been replaced by the new CompletionRequest. These leftovers are: * The return values (int/size_t) in all completion functions. * Our result array that starts indexing at 1. * `WordComplete` mode. I didn't replace them back then because it's tricky to figure out what exactly they are used for and the completion code is relatively untested. I finally got around to writing more tests for the API and understanding the semantics, so I think it's a good time to get rid of them. A few words why those things should be removed/replaced: * The return values are really cryptic, partly redundant and rarely documented. They are also completely ignored by Xcode, so whatever information they contain will end up breaking Xcode's completion mechanism. They are also partly impossible to even implement as we assign negative values special meaning and our completion API sometimes returns size_t. Completion functions are supposed to return -2 to rewrite the current line. We seem to use this in some untested code path to expand the history repeat character to the full command, but I haven't figured out why that doesn't work at the moment. Completion functions return -1 to 'insert the completion character', but that isn't implemented (even though we seem to activate this feature in LLDB sometimes). All positive values have to match the number of results. This is obviously just redundant information as the user can just look at the result list to get that information (which is what Xcode does). * The result array that starts indexing at 1 is obviously unexpected. The first element of the array is reserved for the common prefix of all completions (e.g. "foobar" and "footar" -> "foo"). The idea is that we calculate this to make the life of the API caller easier, but obviously forcing people to have 1-based indices is not helpful (or even worse, forces them to manually copy the results to make it 0-based like Xcode has to do). * The `WordComplete` mode indicates that LLDB should enter a space behind the completion. The idea is that we let the top-level API know that we just provided a full completion. Interestingly we `WordComplete` is just a single bool that somehow represents all N completions. And we always provide full completions in LLDB, so in theory it should always be true. The only use it currently serves is providing redundant information about whether we have a single definitive completion or not (which we already know from the number of results we get). This patch essentially removes `WordComplete` mode and makes the result array indexed from 0. It also removes all return values from all internal completion functions. The only non-redundant information they contain is about rewriting the current line (which is broken), so that functionality was moved to the CompletionRequest API. So you can now do `addCompletion("blub", "description", CompletionMode::RewriteLine)` to do the same. For the SB API we emulate the old behaviour by making the array indexed from 1 again with the common prefix at index 0. I didn't keep the special negative return codes as we either never sent them before (e.g. -2) or we didn't even implement them in the Editline handler (e.g. -1). I tried to keep this patch minimal and I'm aware we can probably now even further simplify a bunch of related code, but I would prefer doing this in follow-up NFC commits Reviewers: JDevlieghere Reviewed By: JDevlieghere Subscribers: arphaman, abidh, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D66536 llvm-svn: 369624
2019-08-22 15:41:23 +08:00
void Variable::AutoComplete(const ExecutionContext &exe_ctx,
CompletionRequest &request) {
CompilerType compiler_type;
PrivateAutoComplete(exe_ctx.GetFramePtr(), request.GetCursorArgumentPrefix(),
"", compiler_type, request);
}