1 //===-- BreakpointResolverFileLine.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/BreakpointResolverFileLine.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/CompileUnit.h" 21 #include "lldb/Symbol/Function.h" 22 #include "lldb/lldb-private-log.h" 23 24 using namespace lldb; 25 using namespace lldb_private; 26 27 //---------------------------------------------------------------------- 28 // BreakpointResolverFileLine: 29 //---------------------------------------------------------------------- 30 BreakpointResolverFileLine::BreakpointResolverFileLine 31 ( 32 Breakpoint *bkpt, 33 const FileSpec &file_spec, 34 uint32_t line_no, 35 bool check_inlines, 36 bool skip_prologue 37 ) : 38 BreakpointResolver (bkpt, BreakpointResolver::FileLineResolver), 39 m_file_spec (file_spec), 40 m_line_number (line_no), 41 m_inlines (check_inlines), 42 m_skip_prologue(skip_prologue) 43 { 44 } 45 46 BreakpointResolverFileLine::~BreakpointResolverFileLine () 47 { 48 } 49 50 Searcher::CallbackReturn 51 BreakpointResolverFileLine::SearchCallback 52 ( 53 SearchFilter &filter, 54 SymbolContext &context, 55 Address *addr, 56 bool containing 57 ) 58 { 59 SymbolContextList sc_list; 60 61 assert (m_breakpoint != NULL); 62 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); 63 64 // There is a tricky bit here. You can have two compilation units that #include the same file, and 65 // 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 66 // other it isn't. If we considered the CU's independently, then in the second inclusion, we'd move the breakpoint 67 // to the next function that actually generated code in the header file. That would end up being confusing. 68 // So instead, we do the CU iterations by hand here, then scan through the complete list of matches, and figure out 69 // the closest line number match, and only set breakpoints on that match. 70 71 // Note also that if file_spec only had a file name and not a directory, there may be many different file spec's in 72 // the resultant list. The closest line match for one will not be right for some totally different file. 73 // So we go through the match list and pull out the sets that have the same file spec in their line_entry 74 // and treat each set separately. 75 76 const size_t num_comp_units = context.module_sp->GetNumCompileUnits(); 77 for (size_t i = 0; i < num_comp_units; i++) 78 { 79 CompUnitSP cu_sp (context.module_sp->GetCompileUnitAtIndex (i)); 80 if (cu_sp) 81 { 82 if (filter.CompUnitPasses(*cu_sp)) 83 cu_sp->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, false, eSymbolContextEverything, sc_list); 84 } 85 } 86 87 while (sc_list.GetSize() > 0) 88 { 89 SymbolContextList tmp_sc_list; 90 unsigned current_idx = 0; 91 SymbolContext sc; 92 bool first_entry = true; 93 94 FileSpec match_file_spec; 95 uint32_t closest_line_number = UINT32_MAX; 96 97 // Pull out the first entry, and all the others that match its file spec, and stuff them in the tmp list. 98 while (current_idx < sc_list.GetSize()) 99 { 100 bool matches; 101 102 sc_list.GetContextAtIndex (current_idx, sc); 103 if (first_entry) 104 { 105 match_file_spec = sc.line_entry.file; 106 matches = true; 107 first_entry = false; 108 } 109 else 110 matches = (sc.line_entry.file == match_file_spec); 111 112 if (matches) 113 { 114 tmp_sc_list.Append (sc); 115 sc_list.RemoveContextAtIndex(current_idx); 116 117 // ResolveSymbolContext will always return a number that is >= the line number you pass in. 118 // So the smaller line number is always better. 119 if (sc.line_entry.line < closest_line_number) 120 closest_line_number = sc.line_entry.line; 121 } 122 else 123 current_idx++; 124 } 125 126 // Okay, we've found the closest line number match, now throw away all the others: 127 128 current_idx = 0; 129 while (current_idx < tmp_sc_list.GetSize()) 130 { 131 if (tmp_sc_list.GetContextAtIndex(current_idx, sc)) 132 { 133 if (sc.line_entry.line != closest_line_number) 134 tmp_sc_list.RemoveContextAtIndex(current_idx); 135 else 136 current_idx++; 137 } 138 } 139 140 // Next go through and see if there are line table entries that are contiguous, and if so keep only the 141 // first of the contiguous range: 142 143 current_idx = 0; 144 std::map<Block *, lldb::addr_t> blocks_with_breakpoints; 145 146 while (current_idx < tmp_sc_list.GetSize()) 147 { 148 if (tmp_sc_list.GetContextAtIndex(current_idx, sc)) 149 { 150 if (blocks_with_breakpoints.find (sc.block) != blocks_with_breakpoints.end()) 151 tmp_sc_list.RemoveContextAtIndex(current_idx); 152 else 153 { 154 blocks_with_breakpoints.insert (std::pair<Block *, lldb::addr_t>(sc.block, sc.line_entry.range.GetBaseAddress().GetFileAddress())); 155 current_idx++; 156 } 157 } 158 } 159 160 // and make breakpoints out of the closest line number match. 161 162 uint32_t tmp_sc_list_size = tmp_sc_list.GetSize(); 163 164 for (uint32_t i = 0; i < tmp_sc_list_size; i++) 165 { 166 if (tmp_sc_list.GetContextAtIndex(i, sc)) 167 { 168 Address line_start = sc.line_entry.range.GetBaseAddress(); 169 if (line_start.IsValid()) 170 { 171 if (filter.AddressPasses(line_start)) 172 { 173 // If the line number is before the prologue end, move it there... 174 bool skipped_prologue = false; 175 if (m_skip_prologue) 176 { 177 if (sc.function) 178 { 179 Address prologue_addr(sc.function->GetAddressRange().GetBaseAddress()); 180 if (prologue_addr.IsValid() && (line_start == prologue_addr)) 181 { 182 const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize(); 183 if (prologue_byte_size) 184 { 185 prologue_addr.Slide(prologue_byte_size); 186 187 if (filter.AddressPasses(prologue_addr)) 188 { 189 skipped_prologue = true; 190 line_start = prologue_addr; 191 } 192 } 193 } 194 } 195 } 196 197 BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(line_start)); 198 if (log && bp_loc_sp && !m_breakpoint->IsInternal()) 199 { 200 StreamString s; 201 bp_loc_sp->GetDescription (&s, lldb::eDescriptionLevelVerbose); 202 log->Printf ("Added location (skipped prologue: %s): %s \n", skipped_prologue ? "yes" : "no", s.GetData()); 203 } 204 } 205 else if (log) 206 { 207 log->Printf ("Breakpoint at file address 0x%" PRIx64 " for %s:%d didn't pass the filter.\n", 208 line_start.GetFileAddress(), 209 m_file_spec.GetFilename().AsCString("<Unknown>"), 210 m_line_number); 211 } 212 } 213 else 214 { 215 if (log) 216 log->Printf ("error: Unable to set breakpoint at file address 0x%" PRIx64 " for %s:%d\n", 217 line_start.GetFileAddress(), 218 m_file_spec.GetFilename().AsCString("<Unknown>"), 219 m_line_number); 220 } 221 } 222 } 223 } 224 225 return Searcher::eCallbackReturnContinue; 226 } 227 228 Searcher::Depth 229 BreakpointResolverFileLine::GetDepth() 230 { 231 return Searcher::eDepthModule; 232 } 233 234 void 235 BreakpointResolverFileLine::GetDescription (Stream *s) 236 { 237 s->Printf ("file = '%s', line = %u", m_file_spec.GetPath().c_str(), m_line_number); 238 } 239 240 void 241 BreakpointResolverFileLine::Dump (Stream *s) const 242 { 243 244 } 245 246