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