llvm-project/lldb/source/Symbol/SymbolVendor.cpp
Greg Clayton 6beaaa680a A few of the issue I have been trying to track down and fix have been due to
the way LLDB lazily gets complete definitions for types within the debug info.
When we run across a class/struct/union definition in the DWARF, we will only
parse the full definition if we need to. This works fine for top level types
that are assigned directly to variables and arguments, but when we have a 
variable with a class, lets say "A" for this example, that has a member:
"B *m_b". Initially we don't need to hunt down a definition for this class
unless we are ever asked to do something with it ("expr m_b->getDecl()" for
example). With my previous approach to lazy type completion, we would be able
to take a "A *a" and get a complete type for it, but we wouldn't be able to
then do an "a->m_b->getDecl()" unless we always expanded all types within a
class prior to handing out the type. Expanding everything is very costly and
it would be great if there were a better way.

A few months ago I worked with the llvm/clang folks to have the 
ExternalASTSource class be able to complete classes if there weren't completed
yet:

class ExternalASTSource {
....

    virtual void
    CompleteType (clang::TagDecl *Tag);
    
    virtual void 
    CompleteType (clang::ObjCInterfaceDecl *Class);
};

This was great, because we can now have the class that is producing the AST
(SymbolFileDWARF and SymbolFileDWARFDebugMap) sign up as external AST sources
and the object that creates the forward declaration types can now also
complete them anywhere within the clang type system.

This patch makes a few major changes:
- lldb_private::Module classes now own the AST context. Previously the TypeList
  objects did.
- The DWARF parsers now sign up as an external AST sources so they can complete
  types.
- All of the pure clang type system wrapper code we have in LLDB (ClangASTContext,
  ClangASTType, and more) can now be iterating through children of any type,
  and if a class/union/struct type (clang::RecordType or ObjC interface) 
  is found that is incomplete, we can ask the AST to get the definition. 
- The SymbolFileDWARFDebugMap class now will create and use a single AST that
  all child SymbolFileDWARF classes will share (much like what happens when
  we have a complete linked DWARF for an executable).
  
We will need to modify some of the ClangUserExpression code to take more 
advantage of this completion ability in the near future. Meanwhile we should
be better off now that we can be accessing any children of variables through
pointers and always be able to resolve the clang type if needed.

llvm-svn: 123613
2011-01-17 03:46:26 +00:00

369 lines
10 KiB
C++

//===-- SymbolVendor.mm -----------------------------------------*- 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/SymbolVendor.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolFile.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// FindPlugin
//
// Platforms can register a callback to use when creating symbol
// vendors to allow for complex debug information file setups, and to
// also allow for finding separate debug information files.
//----------------------------------------------------------------------
SymbolVendor*
SymbolVendor::FindPlugin (Module* module)
{
std::auto_ptr<SymbolVendor> instance_ap;
//----------------------------------------------------------------------
// We currently only have one debug symbol parser...
//----------------------------------------------------------------------
SymbolVendorCreateInstance create_callback;
for (uint32_t idx = 0; (create_callback = PluginManager::GetSymbolVendorCreateCallbackAtIndex(idx)) != NULL; ++idx)
{
instance_ap.reset(create_callback(module));
if (instance_ap.get())
{
// TODO: make sure this symbol vendor is what we want. We
// currently are just returning the first one we find, but
// we may want to call this function only when we have our
// main executable module and then give all symbol vendor
// plug-ins a chance to compete for who wins.
return instance_ap.release();
}
}
// The default implementation just tries to create debug information using the
// file representation for the module.
instance_ap.reset(new SymbolVendor(module));
if (instance_ap.get())
instance_ap->AddSymbolFileRepresendation(module->GetObjectFile());
return instance_ap.release();
}
//----------------------------------------------------------------------
// SymbolVendor constructor
//----------------------------------------------------------------------
SymbolVendor::SymbolVendor(Module *module) :
ModuleChild(module),
m_mutex (Mutex::eMutexTypeRecursive),
m_type_list(),
m_compile_units(),
m_sym_file_ap()
{
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
SymbolVendor::~SymbolVendor()
{
}
//----------------------------------------------------------------------
// Add a represantion given an object file.
//----------------------------------------------------------------------
void
SymbolVendor::AddSymbolFileRepresendation(ObjectFile *obj_file)
{
Mutex::Locker locker(m_mutex);
if (obj_file != NULL)
m_sym_file_ap.reset(SymbolFile::FindPlugin(obj_file));
}
bool
SymbolVendor::SetCompileUnitAtIndex (CompUnitSP& cu, uint32_t idx)
{
Mutex::Locker locker(m_mutex);
const uint32_t num_compile_units = GetNumCompileUnits();
if (idx < num_compile_units)
{
// Fire off an assertion if this compile unit already exists for now.
// The partial parsing should take care of only setting the compile
// unit once, so if this assertion fails, we need to make sure that
// we don't have a race condition, or have a second parse of the same
// compile unit.
assert(m_compile_units[idx].get() == NULL);
m_compile_units[idx] = cu;
return true;
}
return false;
}
uint32_t
SymbolVendor::GetNumCompileUnits()
{
Mutex::Locker locker(m_mutex);
if (m_compile_units.empty())
{
if (m_sym_file_ap.get())
{
// Resize our array of compile unit shared pointers -- which will
// each remain NULL until someone asks for the actual compile unit
// information. When this happens, the symbol file will be asked
// to parse this compile unit information.
m_compile_units.resize(m_sym_file_ap->GetNumCompileUnits());
}
}
return m_compile_units.size();
}
size_t
SymbolVendor::ParseCompileUnitFunctions (const SymbolContext &sc)
{
Mutex::Locker locker(m_mutex);
if (m_sym_file_ap.get())
return m_sym_file_ap->ParseCompileUnitFunctions(sc);
return 0;
}
bool
SymbolVendor::ParseCompileUnitLineTable (const SymbolContext &sc)
{
Mutex::Locker locker(m_mutex);
if (m_sym_file_ap.get())
return m_sym_file_ap->ParseCompileUnitLineTable(sc);
return false;
}
bool
SymbolVendor::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files)
{
Mutex::Locker locker(m_mutex);
if (m_sym_file_ap.get())
return m_sym_file_ap->ParseCompileUnitSupportFiles(sc, support_files);
return false;
}
size_t
SymbolVendor::ParseFunctionBlocks (const SymbolContext &sc)
{
Mutex::Locker locker(m_mutex);
if (m_sym_file_ap.get())
return m_sym_file_ap->ParseFunctionBlocks(sc);
return 0;
}
size_t
SymbolVendor::ParseTypes (const SymbolContext &sc)
{
Mutex::Locker locker(m_mutex);
if (m_sym_file_ap.get())
return m_sym_file_ap->ParseTypes(sc);
return 0;
}
size_t
SymbolVendor::ParseVariablesForContext (const SymbolContext& sc)
{
Mutex::Locker locker(m_mutex);
if (m_sym_file_ap.get())
return m_sym_file_ap->ParseVariablesForContext(sc);
return 0;
}
Type*
SymbolVendor::ResolveTypeUID(lldb::user_id_t type_uid)
{
Mutex::Locker locker(m_mutex);
if (m_sym_file_ap.get())
return m_sym_file_ap->ResolveTypeUID(type_uid);
return NULL;
}
uint32_t
SymbolVendor::ResolveSymbolContext (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc)
{
Mutex::Locker locker(m_mutex);
if (m_sym_file_ap.get())
return m_sym_file_ap->ResolveSymbolContext(so_addr, resolve_scope, sc);
return 0;
}
uint32_t
SymbolVendor::ResolveSymbolContext (const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
{
Mutex::Locker locker(m_mutex);
if (m_sym_file_ap.get())
return m_sym_file_ap->ResolveSymbolContext(file_spec, line, check_inlines, resolve_scope, sc_list);
return 0;
}
uint32_t
SymbolVendor::FindGlobalVariables (const ConstString &name, bool append, uint32_t max_matches, VariableList& variables)
{
Mutex::Locker locker(m_mutex);
if (m_sym_file_ap.get())
return m_sym_file_ap->FindGlobalVariables(name, append, max_matches, variables);
return 0;
}
uint32_t
SymbolVendor::FindGlobalVariables (const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
{
Mutex::Locker locker(m_mutex);
if (m_sym_file_ap.get())
return m_sym_file_ap->FindGlobalVariables(regex, append, max_matches, variables);
return 0;
}
uint32_t
SymbolVendor::FindFunctions(const ConstString &name, uint32_t name_type_mask, bool append, SymbolContextList& sc_list)
{
Mutex::Locker locker(m_mutex);
if (m_sym_file_ap.get())
return m_sym_file_ap->FindFunctions(name, name_type_mask, append, sc_list);
return 0;
}
uint32_t
SymbolVendor::FindFunctions(const RegularExpression& regex, bool append, SymbolContextList& sc_list)
{
Mutex::Locker locker(m_mutex);
if (m_sym_file_ap.get())
return m_sym_file_ap->FindFunctions(regex, append, sc_list);
return 0;
}
uint32_t
SymbolVendor::FindTypes (const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, TypeList& types)
{
Mutex::Locker locker(m_mutex);
if (m_sym_file_ap.get())
return m_sym_file_ap->FindTypes(sc, name, append, max_matches, types);
if (!append)
types.Clear();
return 0;
}
ClangNamespaceDecl
SymbolVendor::FindNamespace(const SymbolContext& sc, const ConstString &name)
{
Mutex::Locker locker(m_mutex);
ClangNamespaceDecl namespace_decl;
if (m_sym_file_ap.get())
namespace_decl = m_sym_file_ap->FindNamespace (sc, name);
return namespace_decl;
}
void
SymbolVendor::Dump(Stream *s)
{
Mutex::Locker locker(m_mutex);
bool show_context = false;
s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
s->Indent();
s->PutCString("SymbolVendor");
if (m_sym_file_ap.get())
{
ObjectFile *objfile = m_sym_file_ap->GetObjectFile();
if (objfile)
{
const FileSpec &objfile_file_spec = objfile->GetFileSpec();
if (objfile_file_spec)
{
s->PutCString(" (");
objfile_file_spec.Dump(s);
s->PutChar(')');
}
}
}
s->EOL();
s->IndentMore();
m_type_list.Dump(s, show_context);
CompileUnitConstIter cu_pos, cu_end;
cu_end = m_compile_units.end();
for (cu_pos = m_compile_units.begin(); cu_pos != cu_end; ++cu_pos)
{
// We currently only dump the compile units that have been parsed
if (cu_pos->get())
(*cu_pos)->Dump(s, show_context);
}
s->IndentLess();
}
CompUnitSP
SymbolVendor::GetCompileUnitAtIndex(uint32_t idx)
{
Mutex::Locker locker(m_mutex);
CompUnitSP cu_sp;
const uint32_t num_compile_units = GetNumCompileUnits();
if (idx < num_compile_units)
{
cu_sp = m_compile_units[idx];
if (cu_sp.get() == NULL)
{
m_compile_units[idx] = m_sym_file_ap->ParseCompileUnitAtIndex(idx);
cu_sp = m_compile_units[idx];
}
}
return cu_sp;
}
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
const char *
SymbolVendor::GetPluginName()
{
return "SymbolVendor";
}
const char *
SymbolVendor::GetShortPluginName()
{
return "vendor-default";
}
uint32_t
SymbolVendor::GetPluginVersion()
{
return 1;
}
void
SymbolVendor::GetPluginCommandHelp (const char *command, Stream *strm)
{
}
Error
SymbolVendor::ExecutePluginCommand (Args &command, Stream *strm)
{
Error error;
error.SetErrorString("No plug-in command are currently supported.");
return error;
}
Log *
SymbolVendor::EnablePluginLogging (Stream *strm, Args &command)
{
return NULL;
}