BreakpointResolver.cpp revision 341825
1//===-- BreakpointResolver.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/BreakpointResolver.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Breakpoint/Breakpoint.h"
17#include "lldb/Breakpoint/BreakpointLocation.h"
18// Have to include the other breakpoint resolver types here so the static
19// create from StructuredData can call them.
20#include "lldb/Breakpoint/BreakpointResolverAddress.h"
21#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
22#include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
23#include "lldb/Breakpoint/BreakpointResolverName.h"
24#include "lldb/Core/Address.h"
25#include "lldb/Core/ModuleList.h"
26#include "lldb/Core/SearchFilter.h"
27#include "lldb/Symbol/CompileUnit.h"
28#include "lldb/Symbol/Function.h"
29#include "lldb/Symbol/SymbolContext.h"
30#include "lldb/Target/Target.h"
31#include "lldb/Utility/Log.h"
32#include "lldb/Utility/Stream.h"
33#include "lldb/Utility/StreamString.h"
34
35using namespace lldb_private;
36using namespace lldb;
37
38//----------------------------------------------------------------------
39// BreakpointResolver:
40//----------------------------------------------------------------------
41const char *BreakpointResolver::g_ty_to_name[] = {"FileAndLine", "Address",
42                                                  "SymbolName",  "SourceRegex",
43                                                  "Exception",   "Unknown"};
44
45const char *BreakpointResolver::g_option_names[static_cast<uint32_t>(
46    BreakpointResolver::OptionNames::LastOptionName)] = {
47    "AddressOffset", "Exact",        "FileName",   "Inlines", "Language",
48    "LineNumber",    "ModuleName",   "NameMask",   "Offset",  "Regex",
49    "SectionName",   "SkipPrologue", "SymbolNames"};
50
51const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) {
52  if (type > LastKnownResolverType)
53    return g_ty_to_name[UnknownResolver];
54
55  return g_ty_to_name[type];
56}
57
58BreakpointResolver::ResolverTy
59BreakpointResolver::NameToResolverTy(llvm::StringRef name) {
60  for (size_t i = 0; i < LastKnownResolverType; i++) {
61    if (name == g_ty_to_name[i])
62      return (ResolverTy)i;
63  }
64  return UnknownResolver;
65}
66
67BreakpointResolver::BreakpointResolver(Breakpoint *bkpt,
68                                       const unsigned char resolverTy,
69                                       lldb::addr_t offset)
70    : m_breakpoint(bkpt), m_offset(offset), SubclassID(resolverTy) {}
71
72BreakpointResolver::~BreakpointResolver() {}
73
74BreakpointResolverSP BreakpointResolver::CreateFromStructuredData(
75    const StructuredData::Dictionary &resolver_dict, Status &error) {
76  BreakpointResolverSP result_sp;
77  if (!resolver_dict.IsValid()) {
78    error.SetErrorString("Can't deserialize from an invalid data object.");
79    return result_sp;
80  }
81
82  llvm::StringRef subclass_name;
83
84  bool success = resolver_dict.GetValueForKeyAsString(
85      GetSerializationSubclassKey(), subclass_name);
86
87  if (!success) {
88    error.SetErrorStringWithFormat(
89        "Resolver data missing subclass resolver key");
90    return result_sp;
91  }
92
93  ResolverTy resolver_type = NameToResolverTy(subclass_name);
94  if (resolver_type == UnknownResolver) {
95    error.SetErrorStringWithFormatv("Unknown resolver type: {0}.",
96                                    subclass_name);
97    return result_sp;
98  }
99
100  StructuredData::Dictionary *subclass_options = nullptr;
101  success = resolver_dict.GetValueForKeyAsDictionary(
102      GetSerializationSubclassOptionsKey(), subclass_options);
103  if (!success || !subclass_options || !subclass_options->IsValid()) {
104    error.SetErrorString("Resolver data missing subclass options key.");
105    return result_sp;
106  }
107
108  lldb::addr_t offset;
109  success = subclass_options->GetValueForKeyAsInteger(
110      GetKey(OptionNames::Offset), offset);
111  if (!success) {
112    error.SetErrorString("Resolver data missing offset options key.");
113    return result_sp;
114  }
115
116  BreakpointResolver *resolver;
117
118  switch (resolver_type) {
119  case FileLineResolver:
120    resolver = BreakpointResolverFileLine::CreateFromStructuredData(
121        nullptr, *subclass_options, error);
122    break;
123  case AddressResolver:
124    resolver = BreakpointResolverAddress::CreateFromStructuredData(
125        nullptr, *subclass_options, error);
126    break;
127  case NameResolver:
128    resolver = BreakpointResolverName::CreateFromStructuredData(
129        nullptr, *subclass_options, error);
130    break;
131  case FileRegexResolver:
132    resolver = BreakpointResolverFileRegex::CreateFromStructuredData(
133        nullptr, *subclass_options, error);
134    break;
135  case ExceptionResolver:
136    error.SetErrorString("Exception resolvers are hard.");
137    break;
138  default:
139    llvm_unreachable("Should never get an unresolvable resolver type.");
140  }
141
142  if (!error.Success()) {
143    return result_sp;
144  } else {
145    // Add on the global offset option:
146    resolver->SetOffset(offset);
147    return BreakpointResolverSP(resolver);
148  }
149}
150
151StructuredData::DictionarySP BreakpointResolver::WrapOptionsDict(
152    StructuredData::DictionarySP options_dict_sp) {
153  if (!options_dict_sp || !options_dict_sp->IsValid())
154    return StructuredData::DictionarySP();
155
156  StructuredData::DictionarySP type_dict_sp(new StructuredData::Dictionary());
157  type_dict_sp->AddStringItem(GetSerializationSubclassKey(), GetResolverName());
158  type_dict_sp->AddItem(GetSerializationSubclassOptionsKey(), options_dict_sp);
159
160  // Add the m_offset to the dictionary:
161  options_dict_sp->AddIntegerItem(GetKey(OptionNames::Offset), m_offset);
162
163  return type_dict_sp;
164}
165
166void BreakpointResolver::SetBreakpoint(Breakpoint *bkpt) {
167  m_breakpoint = bkpt;
168}
169
170void BreakpointResolver::ResolveBreakpointInModules(SearchFilter &filter,
171                                                    ModuleList &modules) {
172  filter.SearchInModuleList(*this, modules);
173}
174
175void BreakpointResolver::ResolveBreakpoint(SearchFilter &filter) {
176  filter.Search(*this);
177}
178
179void BreakpointResolver::SetSCMatchesByLine(SearchFilter &filter,
180                                            SymbolContextList &sc_list,
181                                            bool skip_prologue,
182                                            llvm::StringRef log_ident) {
183  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
184
185  while (sc_list.GetSize() > 0) {
186    SymbolContextList tmp_sc_list;
187    unsigned current_idx = 0;
188    SymbolContext sc;
189    bool first_entry = true;
190
191    FileSpec match_file_spec;
192    FileSpec match_original_file_spec;
193    uint32_t closest_line_number = UINT32_MAX;
194
195    // Pull out the first entry, and all the others that match its file spec,
196    // and stuff them in the tmp list.
197    while (current_idx < sc_list.GetSize()) {
198      bool matches;
199
200      sc_list.GetContextAtIndex(current_idx, sc);
201      if (first_entry) {
202        match_file_spec = sc.line_entry.file;
203        match_original_file_spec = sc.line_entry.original_file;
204        matches = true;
205        first_entry = false;
206      } else
207        matches = ((sc.line_entry.file == match_file_spec) ||
208                   (sc.line_entry.original_file == match_original_file_spec));
209
210      if (matches) {
211        tmp_sc_list.Append(sc);
212        sc_list.RemoveContextAtIndex(current_idx);
213
214        // ResolveSymbolContext will always return a number that is >= the line
215        // number you pass in. So the smaller line number is always better.
216        if (sc.line_entry.line < closest_line_number)
217          closest_line_number = sc.line_entry.line;
218      } else
219        current_idx++;
220    }
221
222    // Okay, we've found the closest line number match, now throw away all the
223    // others:
224
225    current_idx = 0;
226    while (current_idx < tmp_sc_list.GetSize()) {
227      if (tmp_sc_list.GetContextAtIndex(current_idx, sc)) {
228        if (sc.line_entry.line != closest_line_number)
229          tmp_sc_list.RemoveContextAtIndex(current_idx);
230        else
231          current_idx++;
232      }
233    }
234
235    // Next go through and see if there are line table entries that are
236    // contiguous, and if so keep only the first of the contiguous range:
237
238    current_idx = 0;
239    std::map<Block *, lldb::addr_t> blocks_with_breakpoints;
240
241    while (current_idx < tmp_sc_list.GetSize()) {
242      if (tmp_sc_list.GetContextAtIndex(current_idx, sc)) {
243        if (blocks_with_breakpoints.find(sc.block) !=
244            blocks_with_breakpoints.end())
245          tmp_sc_list.RemoveContextAtIndex(current_idx);
246        else {
247          blocks_with_breakpoints.insert(std::pair<Block *, lldb::addr_t>(
248              sc.block, sc.line_entry.range.GetBaseAddress().GetFileAddress()));
249          current_idx++;
250        }
251      }
252    }
253
254    // and make breakpoints out of the closest line number match.
255
256    uint32_t tmp_sc_list_size = tmp_sc_list.GetSize();
257
258    for (uint32_t i = 0; i < tmp_sc_list_size; i++) {
259      if (tmp_sc_list.GetContextAtIndex(i, sc)) {
260        Address line_start = sc.line_entry.range.GetBaseAddress();
261        if (line_start.IsValid()) {
262          if (filter.AddressPasses(line_start)) {
263            // If the line number is before the prologue end, move it there...
264            bool skipped_prologue = false;
265            if (skip_prologue) {
266              if (sc.function) {
267                Address prologue_addr(
268                    sc.function->GetAddressRange().GetBaseAddress());
269                if (prologue_addr.IsValid() && (line_start == prologue_addr)) {
270                  const uint32_t prologue_byte_size =
271                      sc.function->GetPrologueByteSize();
272                  if (prologue_byte_size) {
273                    prologue_addr.Slide(prologue_byte_size);
274
275                    if (filter.AddressPasses(prologue_addr)) {
276                      skipped_prologue = true;
277                      line_start = prologue_addr;
278                    }
279                  }
280                }
281              }
282            }
283
284            BreakpointLocationSP bp_loc_sp(AddLocation(line_start));
285            if (log && bp_loc_sp && !m_breakpoint->IsInternal()) {
286              StreamString s;
287              bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
288              log->Printf("Added location (skipped prologue: %s): %s \n",
289                          skipped_prologue ? "yes" : "no", s.GetData());
290            }
291          } else if (log) {
292            log->Printf("Breakpoint %s at file address 0x%" PRIx64
293                        " didn't pass the filter.\n",
294                        log_ident.str().c_str(), line_start.GetFileAddress());
295          }
296        } else {
297          if (log)
298            log->Printf(
299                "error: Unable to set breakpoint %s at file address 0x%" PRIx64
300                "\n",
301                log_ident.str().c_str(), line_start.GetFileAddress());
302        }
303      }
304    }
305  }
306}
307
308BreakpointLocationSP BreakpointResolver::AddLocation(Address loc_addr,
309                                                     bool *new_location) {
310  loc_addr.Slide(m_offset);
311  return m_breakpoint->AddLocation(loc_addr, new_location);
312}
313
314void BreakpointResolver::SetOffset(lldb::addr_t offset) {
315  // There may already be an offset, so we are actually adjusting location
316  // addresses by the difference.
317  // lldb::addr_t slide = offset - m_offset;
318  // FIXME: We should go fix up all the already set locations for the new slide.
319
320  m_offset = offset;
321}
322