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 #include "lldb/Core/Address.h"
19 #include "lldb/Core/Log.h"
20 #include "lldb/Core/ModuleList.h"
21 #include "lldb/Core/SearchFilter.h"
22 #include "lldb/Core/Stream.h"
23 #include "lldb/Core/StreamString.h"
24 #include "lldb/Symbol/CompileUnit.h"
25 #include "lldb/Symbol/Function.h"
26 #include "lldb/Symbol/SymbolContext.h"
27 #include "lldb/Target/Target.h"
28 
29 using namespace lldb_private;
30 using namespace lldb;
31 
32 //----------------------------------------------------------------------
33 // BreakpointResolver:
34 //----------------------------------------------------------------------
35 BreakpointResolver::BreakpointResolver(Breakpoint *bkpt,
36                                        const unsigned char resolverTy,
37                                        lldb::addr_t offset)
38     : m_breakpoint(bkpt), m_offset(offset), SubclassID(resolverTy) {}
39 
40 BreakpointResolver::~BreakpointResolver() {}
41 
42 void BreakpointResolver::SetBreakpoint(Breakpoint *bkpt) {
43   m_breakpoint = bkpt;
44 }
45 
46 void BreakpointResolver::ResolveBreakpointInModules(SearchFilter &filter,
47                                                     ModuleList &modules) {
48   filter.SearchInModuleList(*this, modules);
49 }
50 
51 void BreakpointResolver::ResolveBreakpoint(SearchFilter &filter) {
52   filter.Search(*this);
53 }
54 
55 void BreakpointResolver::SetSCMatchesByLine(SearchFilter &filter,
56                                             SymbolContextList &sc_list,
57                                             bool skip_prologue,
58                                             const char *log_ident) {
59   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
60 
61   while (sc_list.GetSize() > 0) {
62     SymbolContextList tmp_sc_list;
63     unsigned current_idx = 0;
64     SymbolContext sc;
65     bool first_entry = true;
66 
67     FileSpec match_file_spec;
68     FileSpec match_original_file_spec;
69     uint32_t closest_line_number = UINT32_MAX;
70 
71     // Pull out the first entry, and all the others that match its file spec,
72     // and stuff them in the tmp list.
73     while (current_idx < sc_list.GetSize()) {
74       bool matches;
75 
76       sc_list.GetContextAtIndex(current_idx, sc);
77       if (first_entry) {
78         match_file_spec = sc.line_entry.file;
79         match_original_file_spec = sc.line_entry.original_file;
80         matches = true;
81         first_entry = false;
82       } else
83         matches = ((sc.line_entry.file == match_file_spec) ||
84                    (sc.line_entry.original_file == match_original_file_spec));
85 
86       if (matches) {
87         tmp_sc_list.Append(sc);
88         sc_list.RemoveContextAtIndex(current_idx);
89 
90         // ResolveSymbolContext will always return a number that is >= the line
91         // number you pass in.
92         // So the smaller line number is always better.
93         if (sc.line_entry.line < closest_line_number)
94           closest_line_number = sc.line_entry.line;
95       } else
96         current_idx++;
97     }
98 
99     // Okay, we've found the closest line number match, now throw away all the
100     // others:
101 
102     current_idx = 0;
103     while (current_idx < tmp_sc_list.GetSize()) {
104       if (tmp_sc_list.GetContextAtIndex(current_idx, sc)) {
105         if (sc.line_entry.line != closest_line_number)
106           tmp_sc_list.RemoveContextAtIndex(current_idx);
107         else
108           current_idx++;
109       }
110     }
111 
112     // Next go through and see if there are line table entries that are
113     // contiguous, and if so keep only the
114     // first of the contiguous range:
115 
116     current_idx = 0;
117     std::map<Block *, lldb::addr_t> blocks_with_breakpoints;
118 
119     while (current_idx < tmp_sc_list.GetSize()) {
120       if (tmp_sc_list.GetContextAtIndex(current_idx, sc)) {
121         if (blocks_with_breakpoints.find(sc.block) !=
122             blocks_with_breakpoints.end())
123           tmp_sc_list.RemoveContextAtIndex(current_idx);
124         else {
125           blocks_with_breakpoints.insert(std::pair<Block *, lldb::addr_t>(
126               sc.block, sc.line_entry.range.GetBaseAddress().GetFileAddress()));
127           current_idx++;
128         }
129       }
130     }
131 
132     // and make breakpoints out of the closest line number match.
133 
134     uint32_t tmp_sc_list_size = tmp_sc_list.GetSize();
135 
136     for (uint32_t i = 0; i < tmp_sc_list_size; i++) {
137       if (tmp_sc_list.GetContextAtIndex(i, sc)) {
138         Address line_start = sc.line_entry.range.GetBaseAddress();
139         if (line_start.IsValid()) {
140           if (filter.AddressPasses(line_start)) {
141             // If the line number is before the prologue end, move it there...
142             bool skipped_prologue = false;
143             if (skip_prologue) {
144               if (sc.function) {
145                 Address prologue_addr(
146                     sc.function->GetAddressRange().GetBaseAddress());
147                 if (prologue_addr.IsValid() && (line_start == prologue_addr)) {
148                   const uint32_t prologue_byte_size =
149                       sc.function->GetPrologueByteSize();
150                   if (prologue_byte_size) {
151                     prologue_addr.Slide(prologue_byte_size);
152 
153                     if (filter.AddressPasses(prologue_addr)) {
154                       skipped_prologue = true;
155                       line_start = prologue_addr;
156                     }
157                   }
158                 }
159               }
160             }
161 
162             BreakpointLocationSP bp_loc_sp(AddLocation(line_start));
163             if (log && bp_loc_sp && !m_breakpoint->IsInternal()) {
164               StreamString s;
165               bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
166               log->Printf("Added location (skipped prologue: %s): %s \n",
167                           skipped_prologue ? "yes" : "no", s.GetData());
168             }
169           } else if (log) {
170             log->Printf("Breakpoint %s at file address 0x%" PRIx64
171                         " didn't pass the filter.\n",
172                         log_ident ? log_ident : "",
173                         line_start.GetFileAddress());
174           }
175         } else {
176           if (log)
177             log->Printf(
178                 "error: Unable to set breakpoint %s at file address 0x%" PRIx64
179                 "\n",
180                 log_ident ? log_ident : "", line_start.GetFileAddress());
181         }
182       }
183     }
184   }
185 }
186 
187 BreakpointLocationSP BreakpointResolver::AddLocation(Address loc_addr,
188                                                      bool *new_location) {
189   loc_addr.Slide(m_offset);
190   return m_breakpoint->AddLocation(loc_addr, new_location);
191 }
192 
193 void BreakpointResolver::SetOffset(lldb::addr_t offset) {
194   // There may already be an offset, so we are actually adjusting location
195   // addresses by the difference.
196   // lldb::addr_t slide = offset - m_offset;
197   // FIXME: We should go fix up all the already set locations for the new slide.
198 
199   m_offset = offset;
200 }
201