BreakpointResolverName.cpp revision 263363
1//===-- BreakpointResolverName.cpp ------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/Breakpoint/BreakpointResolverName.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Breakpoint/BreakpointLocation.h"
17#include "lldb/Core/Log.h"
18#include "lldb/Core/Module.h"
19#include "lldb/Core/StreamString.h"
20#include "lldb/Symbol/ClangNamespaceDecl.h"
21#include "lldb/Symbol/Block.h"
22#include "lldb/Symbol/Function.h"
23#include "lldb/Symbol/Symbol.h"
24#include "lldb/Symbol/SymbolContext.h"
25#include "lldb/Target/ObjCLanguageRuntime.h"
26
27using namespace lldb;
28using namespace lldb_private;
29
30BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
31                                                const char *name_cstr,
32                                                uint32_t name_type_mask,
33                                                Breakpoint::MatchType type,
34                                                bool skip_prologue) :
35    BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
36    m_class_name (),
37    m_regex (),
38    m_match_type (type),
39    m_skip_prologue (skip_prologue)
40{
41
42    if (m_match_type == Breakpoint::Regexp)
43    {
44        if (!m_regex.Compile (name_cstr))
45        {
46            Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
47
48            if (log)
49                log->Warning ("function name regexp: \"%s\" did not compile.", name_cstr);
50        }
51    }
52    else
53    {
54        AddNameLookup (ConstString(name_cstr), name_type_mask);
55    }
56}
57
58BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
59                                                const char *names[],
60                                                size_t num_names,
61                                                uint32_t name_type_mask,
62                                                bool skip_prologue) :
63    BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
64    m_match_type (Breakpoint::Exact),
65    m_skip_prologue (skip_prologue)
66{
67    for (size_t i = 0; i < num_names; i++)
68    {
69        AddNameLookup (ConstString (names[i]), name_type_mask);
70    }
71}
72
73BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
74                                                std::vector<std::string> names,
75                                                uint32_t name_type_mask,
76                                                bool skip_prologue) :
77    BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
78    m_match_type (Breakpoint::Exact),
79    m_skip_prologue (skip_prologue)
80{
81    for (const std::string& name : names)
82    {
83        AddNameLookup (ConstString (name.c_str(), name.size()), name_type_mask);
84    }
85}
86
87BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
88                                                RegularExpression &func_regex,
89                                                bool skip_prologue) :
90    BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
91    m_class_name (NULL),
92    m_regex (func_regex),
93    m_match_type (Breakpoint::Regexp),
94    m_skip_prologue (skip_prologue)
95{
96}
97
98BreakpointResolverName::BreakpointResolverName
99(
100    Breakpoint *bkpt,
101    const char *class_name,
102    const char *method,
103    Breakpoint::MatchType type,
104    bool skip_prologue
105) :
106    BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
107    m_class_name (class_name),
108    m_regex (),
109    m_match_type (type),
110    m_skip_prologue (skip_prologue)
111{
112    LookupInfo lookup;
113    lookup.name.SetCString(method);
114    lookup.lookup_name = lookup.name;
115    lookup.name_type_mask = eFunctionNameTypeMethod;
116    lookup.match_name_after_lookup = false;
117    m_lookups.push_back (lookup);
118}
119
120BreakpointResolverName::~BreakpointResolverName ()
121{
122}
123
124void
125BreakpointResolverName::AddNameLookup (const ConstString &name, uint32_t name_type_mask)
126{
127    ObjCLanguageRuntime::MethodName objc_method(name.GetCString(), false);
128    if (objc_method.IsValid(false))
129    {
130        std::vector<ConstString> objc_names;
131        objc_method.GetFullNames(objc_names, true);
132        for (ConstString objc_name : objc_names)
133        {
134            LookupInfo lookup;
135            lookup.name = name;
136            lookup.lookup_name = objc_name;
137            lookup.name_type_mask = eFunctionNameTypeFull;
138            lookup.match_name_after_lookup = false;
139            m_lookups.push_back (lookup);
140        }
141    }
142    else
143    {
144        LookupInfo lookup;
145        lookup.name = name;
146        Module::PrepareForFunctionNameLookup(lookup.name, name_type_mask, lookup.lookup_name, lookup.name_type_mask, lookup.match_name_after_lookup);
147        m_lookups.push_back (lookup);
148    }
149}
150
151
152void
153BreakpointResolverName::LookupInfo::Prune (SymbolContextList &sc_list, size_t start_idx) const
154{
155    if (match_name_after_lookup && name)
156    {
157        SymbolContext sc;
158        size_t i = start_idx;
159        while (i < sc_list.GetSize())
160        {
161            if (!sc_list.GetContextAtIndex(i, sc))
162                break;
163            ConstString full_name (sc.GetFunctionName());
164            if (full_name && ::strstr(full_name.GetCString(), name.GetCString()) == NULL)
165            {
166                sc_list.RemoveContextAtIndex(i);
167            }
168            else
169            {
170                ++i;
171            }
172        }
173    }
174}
175
176
177// FIXME: Right now we look at the module level, and call the module's "FindFunctions".
178// Greg says he will add function tables, maybe at the CompileUnit level to accelerate function
179// lookup.  At that point, we should switch the depth to CompileUnit, and look in these tables.
180
181Searcher::CallbackReturn
182BreakpointResolverName::SearchCallback
183(
184    SearchFilter &filter,
185    SymbolContext &context,
186    Address *addr,
187    bool containing
188)
189{
190    SymbolContextList func_list;
191    //SymbolContextList sym_list;
192
193    uint32_t i;
194    bool new_location;
195    Address break_addr;
196    assert (m_breakpoint != NULL);
197
198    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
199
200    if (m_class_name)
201    {
202        if (log)
203            log->Warning ("Class/method function specification not supported yet.\n");
204        return Searcher::eCallbackReturnStop;
205    }
206    bool filter_by_cu = (filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0;
207    const bool include_symbols = filter_by_cu == false;
208    const bool include_inlines = true;
209    const bool append = true;
210
211    switch (m_match_type)
212    {
213        case Breakpoint::Exact:
214            if (context.module_sp)
215            {
216                for (const LookupInfo &lookup : m_lookups)
217                {
218                    const size_t start_func_idx = func_list.GetSize();
219                    context.module_sp->FindFunctions (lookup.lookup_name,
220                                                      NULL,
221                                                      lookup.name_type_mask,
222                                                      include_symbols,
223                                                      include_inlines,
224                                                      append,
225                                                      func_list);
226                    const size_t end_func_idx = func_list.GetSize();
227
228                    if (start_func_idx < end_func_idx)
229                        lookup.Prune (func_list, start_func_idx);
230                }
231            }
232            break;
233        case Breakpoint::Regexp:
234            if (context.module_sp)
235            {
236                context.module_sp->FindFunctions (m_regex,
237                                                  !filter_by_cu, // include symbols only if we aren't filterning by CU
238                                                  include_inlines,
239                                                  append,
240                                                  func_list);
241            }
242            break;
243        case Breakpoint::Glob:
244            if (log)
245                log->Warning ("glob is not supported yet.");
246            break;
247    }
248
249    // If the filter specifies a Compilation Unit, remove the ones that don't pass at this point.
250    if (filter_by_cu)
251    {
252        uint32_t num_functions = func_list.GetSize();
253
254        for (size_t idx = 0; idx < num_functions; idx++)
255        {
256            SymbolContext sc;
257            func_list.GetContextAtIndex(idx, sc);
258            if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit))
259            {
260                func_list.RemoveContextAtIndex(idx);
261                num_functions--;
262                idx--;
263            }
264        }
265    }
266
267    // Remove any duplicates between the funcion list and the symbol list
268    SymbolContext sc;
269    if (func_list.GetSize())
270    {
271        for (i = 0; i < func_list.GetSize(); i++)
272        {
273            if (func_list.GetContextAtIndex(i, sc))
274            {
275                if (sc.block && sc.block->GetInlinedFunctionInfo())
276                {
277                    if (!sc.block->GetStartAddress(break_addr))
278                        break_addr.Clear();
279                }
280                else if (sc.function)
281                {
282                    break_addr = sc.function->GetAddressRange().GetBaseAddress();
283                    if (m_skip_prologue && break_addr.IsValid())
284                    {
285                        const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
286                        if (prologue_byte_size)
287                            break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
288                    }
289                }
290                else if (sc.symbol)
291                {
292                    if (sc.symbol->GetType() == eSymbolTypeReExported)
293                    {
294                        const Symbol *actual_symbol = sc.symbol->ResolveReExportedSymbol(m_breakpoint->GetTarget());
295                        if (actual_symbol)
296                            break_addr = actual_symbol->GetAddress();
297                    }
298                    else
299                    {
300                        break_addr = sc.symbol->GetAddress();
301                    }
302
303                    if (m_skip_prologue && break_addr.IsValid())
304                    {
305                        const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();
306                        if (prologue_byte_size)
307                            break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
308                    }
309                }
310
311                if (break_addr.IsValid())
312                {
313                    if (filter.AddressPasses(break_addr))
314                    {
315                        BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
316                        if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
317                        {
318                            if (log)
319                            {
320                                StreamString s;
321                                bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
322                                log->Printf ("Added location: %s\n", s.GetData());
323                            }
324                        }
325                    }
326                }
327            }
328        }
329    }
330
331    return Searcher::eCallbackReturnContinue;
332}
333
334Searcher::Depth
335BreakpointResolverName::GetDepth()
336{
337    return Searcher::eDepthModule;
338}
339
340void
341BreakpointResolverName::GetDescription (Stream *s)
342{
343    if (m_match_type == Breakpoint::Regexp)
344        s->Printf("regex = '%s'", m_regex.GetText());
345    else
346    {
347        size_t num_names = m_lookups.size();
348        if (num_names == 1)
349            s->Printf("name = '%s'", m_lookups[0].name.GetCString());
350        else
351        {
352            s->Printf("names = {");
353            for (size_t i = 0; i < num_names - 1; i++)
354            {
355                s->Printf ("'%s', ", m_lookups[i].name.GetCString());
356            }
357            s->Printf ("'%s'}", m_lookups[num_names - 1].name.GetCString());
358        }
359    }
360}
361
362void
363BreakpointResolverName::Dump (Stream *s) const
364{
365
366}
367
368