intelligently. The four name types we currently have are:
eFunctionNameTypeFull = (1 << 1), // The function name.
// For C this is the same as just the name of the function
// For C++ this is the demangled version of the mangled name.
// For ObjC this is the full function signature with the + or
// - and the square brackets and the class and selector
eFunctionNameTypeBase = (1 << 2), // The function name only, no namespaces or arguments and no class
// methods or selectors will be searched.
eFunctionNameTypeMethod = (1 << 3), // Find function by method name (C++) with no namespace or arguments
eFunctionNameTypeSelector = (1 << 4) // Find function by selector name (ObjC) names
this allows much more flexibility when setting breakoints:
(lldb) breakpoint set --name main --basename
(lldb) breakpoint set --name main --fullname
(lldb) breakpoint set --name main --method
(lldb) breakpoint set --name main --selector
The default:
(lldb) breakpoint set --name main
will inspect the name "main" and look for any parens, or if the name starts
with "-[" or "+[" and if any are found then a full name search will happen.
Else a basename search will be the default.
Fixed some command option structures so not all options are required when they
shouldn't be.
Cleaned up the breakpoint output summary.
Made the "image lookup --address <addr>" output much more verbose so it shows
all the important symbol context results. Added a GetDescription method to
many of the SymbolContext objects for the more verbose output.
llvm-svn: 107075
498 lines
13 KiB
C++
498 lines
13 KiB
C++
//===-- SymbolContext.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/SymbolContext.h"
|
|
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Symbol/CompileUnit.h"
|
|
#include "lldb/Symbol/ObjectFile.h"
|
|
#include "lldb/Symbol/Symbol.h"
|
|
#include "lldb/Symbol/SymbolVendor.h"
|
|
#include "lldb/Target/Target.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
SymbolContext::SymbolContext() :
|
|
target_sp (),
|
|
module_sp (),
|
|
comp_unit (NULL),
|
|
function (NULL),
|
|
block (NULL),
|
|
line_entry (),
|
|
symbol (NULL)
|
|
{
|
|
}
|
|
|
|
SymbolContext::SymbolContext(const ModuleSP& m, CompileUnit *cu, Function *f, Block *b, LineEntry *le, Symbol *s) :
|
|
target_sp (),
|
|
module_sp (m),
|
|
comp_unit (cu),
|
|
function (f),
|
|
block (b),
|
|
line_entry (),
|
|
symbol (s)
|
|
{
|
|
if (le)
|
|
line_entry = *le;
|
|
}
|
|
|
|
SymbolContext::SymbolContext(const TargetSP &t, const ModuleSP& m, CompileUnit *cu, Function *f, Block *b, LineEntry *le, Symbol *s) :
|
|
target_sp (t),
|
|
module_sp (m),
|
|
comp_unit (cu),
|
|
function (f),
|
|
block (b),
|
|
line_entry (),
|
|
symbol (s)
|
|
{
|
|
if (le)
|
|
line_entry = *le;
|
|
}
|
|
|
|
SymbolContext::SymbolContext(const SymbolContext& rhs) :
|
|
target_sp (rhs.target_sp),
|
|
module_sp (rhs.module_sp),
|
|
comp_unit (rhs.comp_unit),
|
|
function (rhs.function),
|
|
block (rhs.block),
|
|
line_entry (rhs.line_entry),
|
|
symbol (rhs.symbol)
|
|
{
|
|
}
|
|
|
|
|
|
SymbolContext::SymbolContext (SymbolContextScope *sc_scope) :
|
|
target_sp (),
|
|
module_sp (),
|
|
comp_unit (NULL),
|
|
function (NULL),
|
|
block (NULL),
|
|
line_entry (),
|
|
symbol (NULL)
|
|
{
|
|
sc_scope->CalculateSymbolContext (this);
|
|
}
|
|
|
|
const SymbolContext&
|
|
SymbolContext::operator= (const SymbolContext& rhs)
|
|
{
|
|
if (this != &rhs)
|
|
{
|
|
target_sp = rhs.target_sp;
|
|
module_sp = rhs.module_sp;
|
|
comp_unit = rhs.comp_unit;
|
|
function = rhs.function;
|
|
block = rhs.block;
|
|
line_entry = rhs.line_entry;
|
|
symbol = rhs.symbol;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void
|
|
SymbolContext::Clear()
|
|
{
|
|
target_sp.reset();
|
|
module_sp.reset();
|
|
comp_unit = NULL;
|
|
function = NULL;
|
|
block = NULL;
|
|
line_entry.Clear();
|
|
symbol = NULL;
|
|
}
|
|
|
|
void
|
|
SymbolContext::DumpStopContext
|
|
(
|
|
Stream *s,
|
|
ExecutionContextScope *exe_scope,
|
|
const Address &addr,
|
|
bool show_module
|
|
) const
|
|
{
|
|
Process *process = NULL;
|
|
if (exe_scope)
|
|
process = exe_scope->CalculateProcess();
|
|
addr_t load_addr = addr.GetLoadAddress (process);
|
|
|
|
if (show_module && module_sp)
|
|
{
|
|
*s << module_sp->GetFileSpec().GetFilename() << '`';
|
|
}
|
|
|
|
if (function != NULL)
|
|
{
|
|
if (function->GetMangled().GetName())
|
|
function->GetMangled().GetName().Dump(s);
|
|
|
|
const addr_t func_load_addr = function->GetAddressRange().GetBaseAddress().GetLoadAddress(process);
|
|
if (load_addr > func_load_addr)
|
|
s->Printf(" + %llu", load_addr - func_load_addr);
|
|
|
|
if (block != NULL)
|
|
{
|
|
s->IndentMore();
|
|
block->DumpStopContext(s, this);
|
|
s->IndentLess();
|
|
}
|
|
else
|
|
{
|
|
if (line_entry.IsValid())
|
|
{
|
|
s->PutCString(" at ");
|
|
if (line_entry.DumpStopContext(s))
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else if (symbol != NULL)
|
|
{
|
|
symbol->GetMangled().GetName().Dump(s);
|
|
|
|
if (symbol->GetAddressRangePtr())
|
|
{
|
|
const addr_t sym_load_addr = symbol->GetAddressRangePtr()->GetBaseAddress().GetLoadAddress(process);
|
|
if (load_addr > sym_load_addr)
|
|
s->Printf(" + %llu", load_addr - sym_load_addr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
addr.Dump(s, exe_scope, Address::DumpStyleModuleWithFileAddress);
|
|
}
|
|
}
|
|
|
|
void
|
|
SymbolContext::GetDescription(Stream *s, lldb::DescriptionLevel level, Process *process) const
|
|
{
|
|
if (module_sp)
|
|
{
|
|
s->Indent(" Module: \"");
|
|
module_sp->GetFileSpec().Dump(s);
|
|
s->PutChar('"');
|
|
s->EOL();
|
|
}
|
|
|
|
if (comp_unit != NULL)
|
|
{
|
|
s->Indent("CompileUnit: ");
|
|
comp_unit->GetDescription (s, level);
|
|
s->EOL();
|
|
}
|
|
|
|
if (function != NULL)
|
|
{
|
|
s->Indent(" Function: ");
|
|
function->GetDescription (s, level, process);
|
|
s->EOL();
|
|
|
|
Type *func_type = function->GetType();
|
|
if (func_type)
|
|
{
|
|
s->Indent(" FuncType: ");
|
|
func_type->GetDescription (s, level, false);
|
|
s->EOL();
|
|
}
|
|
}
|
|
|
|
if (block != NULL)
|
|
{
|
|
std::vector<Block *> blocks;
|
|
blocks.push_back (block);
|
|
Block *parent_block = block->GetParent();
|
|
|
|
while (parent_block)
|
|
{
|
|
blocks.push_back (parent_block);
|
|
parent_block = parent_block->GetParent();
|
|
}
|
|
std::vector<Block *>::reverse_iterator pos;
|
|
std::vector<Block *>::reverse_iterator begin = blocks.rbegin();
|
|
std::vector<Block *>::reverse_iterator end = blocks.rend();
|
|
for (pos = begin; pos != end; ++pos)
|
|
{
|
|
if (pos == begin)
|
|
s->Indent(" Blocks: ");
|
|
else
|
|
s->Indent(" ");
|
|
(*pos)->GetDescription(s, level, process);
|
|
s->EOL();
|
|
}
|
|
}
|
|
|
|
if (line_entry.IsValid())
|
|
{
|
|
s->Indent(" LineEntry: ");
|
|
line_entry.GetDescription (s, level, comp_unit, process, false);
|
|
s->EOL();
|
|
}
|
|
|
|
if (symbol != NULL)
|
|
{
|
|
s->Indent(" Symbol: ");
|
|
symbol->GetDescription(s, level, process);
|
|
s->EOL();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
SymbolContext::Dump(Stream *s, Process *process) const
|
|
{
|
|
*s << (void *)this << ": ";
|
|
s->Indent();
|
|
s->PutCString("SymbolContext");
|
|
s->IndentMore();
|
|
s->EOL();
|
|
s->IndentMore();
|
|
s->Indent();
|
|
*s << "Module = " << (void *)module_sp.get() << ' ';
|
|
if (module_sp)
|
|
module_sp->GetFileSpec().Dump(s);
|
|
s->EOL();
|
|
s->Indent();
|
|
*s << "CompileUnit = " << (void *)comp_unit;
|
|
if (comp_unit != NULL)
|
|
*s << " {0x" << comp_unit->GetID() << "} " << *(dynamic_cast<FileSpec*> (comp_unit));
|
|
s->EOL();
|
|
s->Indent();
|
|
*s << "Function = " << (void *)function;
|
|
if (function != NULL)
|
|
{
|
|
*s << " {0x" << function->GetID() << "} " << function->GetType()->GetName() << ", address-range = ";
|
|
function->GetAddressRange().Dump(s, process, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress);
|
|
s->EOL();
|
|
s->Indent();
|
|
Type* func_type = function->GetType();
|
|
if (func_type)
|
|
{
|
|
*s << " Type = ";
|
|
func_type->Dump (s, false);
|
|
}
|
|
}
|
|
s->EOL();
|
|
s->Indent();
|
|
*s << "Block = " << (void *)block;
|
|
if (block != NULL)
|
|
*s << " {0x" << block->GetID() << '}';
|
|
// Dump the block and pass it a negative depth to we print all the parent blocks
|
|
//if (block != NULL)
|
|
// block->Dump(s, function->GetFileAddress(), INT_MIN);
|
|
s->EOL();
|
|
s->Indent();
|
|
*s << "LineEntry = ";
|
|
line_entry.Dump (s, process, true, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress, true);
|
|
s->EOL();
|
|
s->Indent();
|
|
*s << "Symbol = " << (void *)symbol;
|
|
if (symbol != NULL && symbol->GetMangled())
|
|
*s << ' ' << symbol->GetMangled().GetName().AsCString();
|
|
s->EOL();
|
|
s->IndentLess();
|
|
s->IndentLess();
|
|
}
|
|
|
|
bool
|
|
lldb_private::operator== (const SymbolContext& lhs, const SymbolContext& rhs)
|
|
{
|
|
return lhs.target_sp.get() == rhs.target_sp.get() &&
|
|
lhs.module_sp.get() == rhs.module_sp.get() &&
|
|
lhs.comp_unit == rhs.comp_unit &&
|
|
lhs.function == rhs.function &&
|
|
LineEntry::Compare(lhs.line_entry, rhs.line_entry) == 0 &&
|
|
lhs.symbol == rhs.symbol;
|
|
}
|
|
|
|
bool
|
|
lldb_private::operator!= (const SymbolContext& lhs, const SymbolContext& rhs)
|
|
{
|
|
return lhs.target_sp.get() != rhs.target_sp.get() ||
|
|
lhs.module_sp.get() != rhs.module_sp.get() ||
|
|
lhs.comp_unit != rhs.comp_unit ||
|
|
lhs.function != rhs.function ||
|
|
LineEntry::Compare(lhs.line_entry, rhs.line_entry) != 0 ||
|
|
lhs.symbol != rhs.symbol;
|
|
}
|
|
|
|
bool
|
|
SymbolContext::GetAddressRange (uint32_t scope, AddressRange &range) const
|
|
{
|
|
if ((scope & eSymbolContextLineEntry) && line_entry.IsValid())
|
|
{
|
|
range = line_entry.range;
|
|
return true;
|
|
}
|
|
else if ((scope & eSymbolContextFunction) && function != NULL)
|
|
{
|
|
range = function->GetAddressRange();
|
|
return true;
|
|
}
|
|
else if ((scope & eSymbolContextSymbol) && symbol != NULL && symbol->GetAddressRangePtr())
|
|
{
|
|
range = *symbol->GetAddressRangePtr();
|
|
|
|
if (range.GetByteSize() == 0)
|
|
{
|
|
if (module_sp)
|
|
{
|
|
ObjectFile *objfile = module_sp->GetObjectFile();
|
|
if (objfile)
|
|
{
|
|
Symtab *symtab = objfile->GetSymtab();
|
|
if (symtab)
|
|
range.SetByteSize(symtab->CalculateSymbolSize (symbol));
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
range.Clear();
|
|
return false;
|
|
}
|
|
|
|
|
|
Function *
|
|
SymbolContext::FindFunctionByName (const char *name) const
|
|
{
|
|
ConstString name_const_str (name);
|
|
if (function != NULL)
|
|
{
|
|
// FIXME: Look in the class of the current function, if it exists,
|
|
// for methods matching name.
|
|
}
|
|
|
|
//
|
|
if (comp_unit != NULL)
|
|
{
|
|
// Make sure we've read in all the functions. We should be able to check and see
|
|
// if there's one by this name present before we do this...
|
|
module_sp->GetSymbolVendor()->ParseCompileUnitFunctions(*this);
|
|
uint32_t func_idx;
|
|
lldb::FunctionSP func_sp;
|
|
for (func_idx = 0; (func_sp = comp_unit->GetFunctionAtIndex(func_idx)) != NULL; ++func_idx)
|
|
{
|
|
if (func_sp->GetMangled().GetName() == name_const_str)
|
|
return func_sp.get();
|
|
}
|
|
}
|
|
if (module_sp != NULL)
|
|
{
|
|
SymbolContextList sc_matches;
|
|
if (module_sp->FindFunctions (name_const_str, eFunctionNameTypeBase | eFunctionNameTypeFull, false, sc_matches) > 0)
|
|
{
|
|
SymbolContext sc;
|
|
sc_matches.GetContextAtIndex (0, sc);
|
|
return sc.function;
|
|
}
|
|
}
|
|
|
|
if (target_sp)
|
|
{
|
|
SymbolContextList sc_matches;
|
|
if (target_sp->GetImages().FindFunctions (name_const_str, eFunctionNameTypeBase | eFunctionNameTypeFull, sc_matches) > 0)
|
|
{
|
|
SymbolContext sc;
|
|
sc_matches.GetContextAtIndex (0, sc);
|
|
return sc.function;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
lldb::VariableSP
|
|
SymbolContext::FindVariableByName (const char *name) const
|
|
{
|
|
lldb::VariableSP return_value;
|
|
return return_value;
|
|
}
|
|
|
|
lldb::TypeSP
|
|
SymbolContext::FindTypeByName (const char *name) const
|
|
{
|
|
lldb::TypeSP return_value;
|
|
return return_value;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// SymbolContextList
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
SymbolContextList::SymbolContextList() :
|
|
m_symbol_contexts()
|
|
{
|
|
}
|
|
|
|
SymbolContextList::~SymbolContextList()
|
|
{
|
|
}
|
|
|
|
void
|
|
SymbolContextList::Append(const SymbolContext& sc)
|
|
{
|
|
m_symbol_contexts.push_back(sc);
|
|
}
|
|
|
|
void
|
|
SymbolContextList::Clear()
|
|
{
|
|
m_symbol_contexts.clear();
|
|
}
|
|
|
|
void
|
|
SymbolContextList::Dump(Stream *s, Process *process) const
|
|
{
|
|
|
|
*s << (void *)this << ": ";
|
|
s->Indent();
|
|
s->PutCString("SymbolContextList");
|
|
s->EOL();
|
|
s->IndentMore();
|
|
|
|
collection::const_iterator pos, end = m_symbol_contexts.end();
|
|
for (pos = m_symbol_contexts.begin(); pos != end; ++pos)
|
|
{
|
|
pos->Dump(s, process);
|
|
}
|
|
s->IndentLess();
|
|
}
|
|
|
|
bool
|
|
SymbolContextList::GetContextAtIndex(uint32_t idx, SymbolContext& sc) const
|
|
{
|
|
if (idx < m_symbol_contexts.size())
|
|
{
|
|
sc = m_symbol_contexts[idx];
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
SymbolContextList::RemoveContextAtIndex (uint32_t idx)
|
|
{
|
|
if (idx < m_symbol_contexts.size())
|
|
{
|
|
m_symbol_contexts.erase(m_symbol_contexts.begin() + idx);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
uint32_t
|
|
SymbolContextList::GetSize() const
|
|
{
|
|
return m_symbol_contexts.size();
|
|
}
|