Files
llvm/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp

231 lines
9.0 KiB
C++
Raw Normal View History

//===-- BreakpointResolverFileLine.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/BreakpointResolverFileLine.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Log.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-29 21:13:06 +00:00
#include "lldb/Core/Module.h"
#include "lldb/Core/StreamString.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-29 21:13:06 +00:00
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
#include "lldb/lldb-private-log.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// BreakpointResolverFileLine:
//----------------------------------------------------------------------
BreakpointResolverFileLine::BreakpointResolverFileLine
(
Breakpoint *bkpt,
const FileSpec &file_spec,
uint32_t line_no,
bool check_inlines,
bool skip_prologue
) :
BreakpointResolver (bkpt, BreakpointResolver::FileLineResolver),
m_file_spec (file_spec),
m_line_number (line_no),
m_inlines (check_inlines),
m_skip_prologue(skip_prologue)
{
}
BreakpointResolverFileLine::~BreakpointResolverFileLine ()
{
}
Searcher::CallbackReturn
BreakpointResolverFileLine::SearchCallback
(
SearchFilter &filter,
SymbolContext &context,
Address *addr,
bool containing
)
{
SymbolContextList sc_list;
assert (m_breakpoint != NULL);
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
// There is a tricky bit here. You can have two compilation units that #include the same file, and
// in one of them the function at m_line_number is used (and so code and a line entry for it is generated) but in the
// other it isn't. If we considered the CU's independently, then in the second inclusion, we'd move the breakpoint
// to the next function that actually generated code in the header file. That would end up being confusing.
// So instead, we do the CU iterations by hand here, then scan through the complete list of matches, and figure out
// the closest line number match, and only set breakpoints on that match.
// Note also that if file_spec only had a file name and not a directory, there may be many different file spec's in
// the resultant list. The closest line match for one will not be right for some totally different file.
// So we go through the match list and pull out the sets that have the same file spec in their line_entry
// and treat each set separately.
uint32_t num_comp_units = context.module_sp->GetNumCompileUnits();
for (uint32_t i = 0; i < num_comp_units; i++)
{
CompUnitSP cu_sp (context.module_sp->GetCompileUnitAtIndex (i));
if (cu_sp)
{
if (filter.CompUnitPasses(*cu_sp))
cu_sp->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, false, eSymbolContextEverything, sc_list);
}
}
while (sc_list.GetSize() > 0)
{
SymbolContextList tmp_sc_list;
int current_idx = 0;
SymbolContext sc;
bool first_entry = true;
FileSpec match_file_spec;
uint32_t closest_line_number = UINT32_MAX;
// Pull out the first entry, and all the others that match its file spec, and stuff them in the tmp list.
while (current_idx < sc_list.GetSize())
{
bool matches;
sc_list.GetContextAtIndex (current_idx, sc);
if (first_entry)
{
match_file_spec = sc.line_entry.file;
matches = true;
first_entry = false;
}
else
matches = (sc.line_entry.file == match_file_spec);
if (matches)
{
tmp_sc_list.Append (sc);
sc_list.RemoveContextAtIndex(current_idx);
// ResolveSymbolContext will always return a number that is >= the line number you pass in.
// So the smaller line number is always better.
if (sc.line_entry.line < closest_line_number)
closest_line_number = sc.line_entry.line;
}
else
current_idx++;
}
// Okay, we've found the closest line number match, now throw away all the others,
// and make breakpoints out of the closest line number match.
uint32_t tmp_sc_list_size = tmp_sc_list.GetSize();
for (uint32_t i = 0; i < tmp_sc_list_size; i++)
{
SymbolContext sc;
if (tmp_sc_list.GetContextAtIndex(i, sc))
{
if (sc.line_entry.line == closest_line_number)
{
Address line_start = sc.line_entry.range.GetBaseAddress();
if (line_start.IsValid())
{
if (filter.AddressPasses(line_start))
{
// If the line number is before the prologue end, move it there...
bool skipped_prologue = false;
if (m_skip_prologue)
{
if (sc.function)
{
Address prologue_addr(sc.function->GetAddressRange().GetBaseAddress());
if (prologue_addr.IsValid() && (line_start == prologue_addr))
{
const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
if (prologue_byte_size)
{
prologue_addr.Slide(prologue_byte_size);
if (filter.AddressPasses(prologue_addr))
{
skipped_prologue = true;
line_start = prologue_addr;
}
}
}
}
}
BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(line_start));
if (log && bp_loc_sp && !m_breakpoint->IsInternal())
{
StreamString s;
bp_loc_sp->GetDescription (&s, lldb::eDescriptionLevelVerbose);
log->Printf ("Added location (skipped prologue: %s): %s \n", skipped_prologue ? "yes" : "no", s.GetData());
}
}
else if (log)
{
log->Printf ("Breakpoint at file address 0x%" PRIx64 " for %s:%d didn't pass the filter.\n",
line_start.GetFileAddress(),
m_file_spec.GetFilename().AsCString("<Unknown>"),
m_line_number);
}
}
else
{
if (log)
log->Printf ("error: Unable to set breakpoint at file address 0x%" PRIx64 " for %s:%d\n",
line_start.GetFileAddress(),
m_file_spec.GetFilename().AsCString("<Unknown>"),
m_line_number);
}
}
else
{
#if 0
s << "error: Breakpoint at '" << pos->c_str() << "' isn't resolved yet: \n";
if (sc.line_entry.address.Dump(&s, Address::DumpStyleSectionNameOffset))
s.EOL();
if (sc.line_entry.address.Dump(&s, Address::DumpStyleSectionPointerOffset))
s.EOL();
if (sc.line_entry.address.Dump(&s, Address::DumpStyleFileAddress))
s.EOL();
if (sc.line_entry.address.Dump(&s, Address::DumpStyleLoadAddress))
s.EOL();
#endif
}
}
}
}
return Searcher::eCallbackReturnContinue;
}
Searcher::Depth
BreakpointResolverFileLine::GetDepth()
{
return Searcher::eDepthModule;
}
void
BreakpointResolverFileLine::GetDescription (Stream *s)
{
Added function name types to allow us to set breakpoints by name more 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
2010-06-28 21:30:43 +00:00
s->Printf ("file ='%s', line = %u", m_file_spec.GetFilename().AsCString(), m_line_number);
}
void
BreakpointResolverFileLine::Dump (Stream *s) const
{
}