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