Files
llvm/lldb/source/Breakpoint/BreakpointResolverName.cpp
Greg Clayton 385aa28cf6 Did some work on the "register read" command to only show the first register
set by default when dumping registers. If you want to see all of the register
sets you can use the "--all" option:

(lldb) register read --all

If you want to just see some register sets, you can currently specify them
by index:

(lldb) register read --set 0 --set 2

We need to get shorter register set names soon so we can specify the register
sets by name without having to type too much. I will make this change soon.

You can also have any integer encoded registers resolve the address values
back to any code or data from the object files using the "--lookup" option.
Below is sample output when stopped in the libc function "puts" with some
const strings in registers:

Process 8973 stopped
* thread #1: tid = 0x2c03, 0x00007fff828fa30f libSystem.B.dylib`puts + 1, stop reason = instruction step into
  frame #0: 0x00007fff828fa30f libSystem.B.dylib`puts + 1
(lldb) register read --lookup 
General Purpose Registers:
  rax          = 0x0000000100000e98  "----------------------------------------------------------------------"
  rbx          = 0x0000000000000000
  rcx          = 0x0000000000000001  
  rdx          = 0x0000000000000000
  rdi          = 0x0000000100000e98  "----------------------------------------------------------------------"
  rsi          = 0x0000000100800000
  rbp          = 0x00007fff5fbff710
  rsp          = 0x00007fff5fbff280
  r8           = 0x0000000000000040  
  r9           = 0x0000000000000000
  r10          = 0x0000000000000000
  r11          = 0x0000000000000246  
  r12          = 0x0000000000000000
  r13          = 0x0000000000000000
  r14          = 0x0000000000000000
  r15          = 0x0000000000000000
  rip          = 0x00007fff828fa30f  libSystem.B.dylib`puts + 1
  rflags       = 0x0000000000000246  
  cs           = 0x0000000000000027  
  fs           = 0x0000000000000000
  gs           = 0x0000000000000000

As we can see, we see two constant strings and the PC (register "rip") is 
showing the code it resolves to.

I fixed the register "--format" option to work as expected.

Added a setting to disable skipping the function prologue when setting 
breakpoints as a target settings variable:

(lldb) settings set target.skip-prologue false

Updated the user settings controller boolean value handler funciton to be able
to take the default value so it can correctly respond to the eVarSetOperationClear
operation.

Did some usability work on the OptionValue classes.

Fixed the "image lookup" command to correctly respond to the "--verbose" 
option and display the detailed symbol context information when looking up
line table entries and functions by name. This previously was only working
for address lookups.

llvm-svn: 129977
2011-04-22 03:55:06 +00:00

383 lines
12 KiB
C++

//===-- BreakpointResolverName.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/Breakpoint/BreakpointResolverName.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Target/Target.h"
using namespace lldb;
using namespace lldb_private;
BreakpointResolverName::BreakpointResolverName
(
Breakpoint *bkpt,
const char *func_name,
uint32_t func_name_type_mask,
Breakpoint::MatchType type
) :
BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
m_func_name (),
m_basename_filter (),
m_func_name_type_mask (func_name_type_mask),
m_class_name (),
m_regex (),
m_match_type (type)
{
if (func_name_type_mask == eFunctionNameTypeAuto)
{
if ((::strchr (func_name, '(' ) != NULL) ||
(::strstr (func_name, "-[") == func_name) ||
(::strstr (func_name, "+[") == func_name))
{
// We have a name that contains an open parens, or starts with
// "+[" or "-[", so this looks like a complete function prototype
m_func_name_type_mask = eFunctionNameTypeFull;
}
else
{
// We don't have a full function name, but we might have a partial
// function basename with namespaces or classes
if (::strstr (func_name, "::") != NULL)
{
// Keep the full name in "m_basename_filter"
m_basename_filter = func_name;
// Now set "m_func_name" to just the function basename
m_func_name.SetCString(m_basename_filter.c_str() + m_basename_filter.rfind("::") + 2);
// We have a name with a double colon which means we have a
// function name that is a C++ method or a function in a C++
// namespace
m_func_name_type_mask = eFunctionNameTypeBase | eFunctionNameTypeMethod;
}
else if (::strstr (func_name, ":") != NULL)
{
// Single colon => selector
m_func_name_type_mask = eFunctionNameTypeSelector;
}
else
{
// just a basename by default
m_func_name_type_mask = eFunctionNameTypeBase;
}
}
}
if (!m_func_name)
m_func_name.SetCString(func_name);
if (m_match_type == Breakpoint::Regexp)
{
if (!m_regex.Compile (m_func_name.AsCString()))
{
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Warning ("function name regexp: \"%s\" did not compile.", m_func_name.AsCString());
}
}
}
BreakpointResolverName::BreakpointResolverName
(
Breakpoint *bkpt,
RegularExpression &func_regex
) :
BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
m_func_name (NULL),
m_class_name (NULL),
m_regex (func_regex),
m_match_type (Breakpoint::Regexp)
{
}
BreakpointResolverName::BreakpointResolverName
(
Breakpoint *bkpt,
const char *class_name,
const char *method,
Breakpoint::MatchType type
) :
BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
m_func_name (method),
m_class_name (class_name),
m_regex (),
m_match_type (type)
{
}
BreakpointResolverName::~BreakpointResolverName ()
{
}
// FIXME: Right now we look at the module level, and call the module's "FindFunctions".
// Greg says he will add function tables, maybe at the CompileUnit level to accelerate function
// lookup. At that point, we should switch the depth to CompileUnit, and look in these tables.
Searcher::CallbackReturn
BreakpointResolverName::SearchCallback
(
SearchFilter &filter,
SymbolContext &context,
Address *addr,
bool containing
)
{
SymbolContextList func_list;
SymbolContextList sym_list;
bool skip_prologue = true;
uint32_t i;
bool new_location;
SymbolContext sc;
Address break_addr;
assert (m_breakpoint != NULL);
if (context.target_sp)
{
skip_prologue = context.target_sp->GetSkipPrologue();
}
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
if (m_class_name)
{
if (log)
log->Warning ("Class/method function specification not supported yet.\n");
return Searcher::eCallbackReturnStop;
}
const bool include_symbols = false;
const bool append = false;
switch (m_match_type)
{
case Breakpoint::Exact:
if (context.module_sp)
{
if (m_func_name_type_mask & (eFunctionNameTypeBase | eFunctionNameTypeFull))
context.module_sp->FindSymbolsWithNameAndType (m_func_name, eSymbolTypeCode, sym_list);
context.module_sp->FindFunctions (m_func_name,
m_func_name_type_mask,
include_symbols,
append,
func_list);
}
break;
case Breakpoint::Regexp:
if (context.module_sp)
{
context.module_sp->FindSymbolsMatchingRegExAndType (m_regex, eSymbolTypeCode, sym_list);
context.module_sp->FindFunctions (m_regex,
include_symbols,
append,
func_list);
}
break;
case Breakpoint::Glob:
if (log)
log->Warning ("glob is not supported yet.");
break;
}
if (!m_basename_filter.empty())
{
// Filter out any matches whose names don't contain the basename filter
const char *basename_filter = m_basename_filter.c_str();
if (func_list.GetSize())
{
bool remove = false;
for (i = 0; i < func_list.GetSize(); remove = false)
{
if (func_list.GetContextAtIndex(i, sc) == false)
remove = true;
else if (sc.function == NULL)
remove = true;
else
{
const InlineFunctionInfo* inlined_info = NULL;
if (sc.block)
inlined_info = sc.block->GetInlinedFunctionInfo();
if (inlined_info)
{
if (::strstr (inlined_info->GetName().AsCString(), basename_filter) == NULL)
remove = true;
}
else if (::strstr (sc.function->GetName().AsCString(), basename_filter) == NULL)
remove = true;
}
if (remove)
{
func_list.RemoveContextAtIndex(i);
continue;
}
i++;
}
}
if (sym_list.GetSize())
{
bool remove = false;
for (i = 0; i < sym_list.GetSize(); remove = false)
{
if (sym_list.GetContextAtIndex(i, sc) == false)
remove = true;
else if (sc.symbol == NULL)
remove = true;
else if (::strstr (sc.symbol->GetName().AsCString(), basename_filter) == NULL)
remove = true;
if (remove)
{
sym_list.RemoveContextAtIndex(i);
continue;
}
i++;
}
}
}
// Remove any duplicates between the funcion list and the symbol list
if (func_list.GetSize())
{
for (i = 0; i < func_list.GetSize(); i++)
{
if (func_list.GetContextAtIndex(i, sc) == false)
continue;
if (sc.function == NULL)
continue;
uint32_t j = 0;
while (j < sym_list.GetSize())
{
SymbolContext symbol_sc;
if (sym_list.GetContextAtIndex(j, symbol_sc))
{
if (symbol_sc.symbol && symbol_sc.symbol->GetAddressRangePtr())
{
if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddressRangePtr()->GetBaseAddress())
{
sym_list.RemoveContextAtIndex(j);
continue; // Don't increment j
}
}
}
j++;
}
}
for (i = 0; i < func_list.GetSize(); i++)
{
if (func_list.GetContextAtIndex(i, sc))
{
if (sc.block && sc.block->GetInlinedFunctionInfo())
{
if (!sc.block->GetStartAddress(break_addr))
break_addr.Clear();
}
else if (sc.function)
{
break_addr = sc.function->GetAddressRange().GetBaseAddress();
if (skip_prologue)
{
if (break_addr.IsValid())
{
const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
if (prologue_byte_size)
break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
}
}
}
if (break_addr.IsValid())
{
if (filter.AddressPasses(break_addr))
{
BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
{
if (log)
{
StreamString s;
bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
log->Printf ("Added location: %s\n", s.GetData());
}
}
}
}
}
}
}
for (i = 0; i < sym_list.GetSize(); i++)
{
if (sym_list.GetContextAtIndex(i, sc))
{
if (sc.symbol && sc.symbol->GetAddressRangePtr())
{
break_addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress();
if (skip_prologue)
{
const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();
if (prologue_byte_size)
break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
}
if (filter.AddressPasses(break_addr))
{
BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
{
StreamString s;
bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
if (log)
log->Printf ("Added location: %s\n", s.GetData());
}
}
}
}
}
return Searcher::eCallbackReturnContinue;
}
Searcher::Depth
BreakpointResolverName::GetDepth()
{
return Searcher::eDepthModule;
}
void
BreakpointResolverName::GetDescription (Stream *s)
{
if (m_match_type == Breakpoint::Regexp)
s->Printf("regex = '%s'", m_regex.GetText());
else if (m_basename_filter.empty())
s->Printf("name = '%s'", m_func_name.AsCString());
else
s->Printf("name = '%s'", m_basename_filter.c_str());
}
void
BreakpointResolverName::Dump (Stream *s) const
{
}