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 (cu_sp) 76 { 77 if (filter.CompUnitPasses(*cu_sp)) 78 cu_sp->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, false, eSymbolContextEverything, sc_list); 79 } 80 } 81 82 while (sc_list.GetSize() > 0) 83 { 84 SymbolContextList tmp_sc_list; 85 int current_idx = 0; 86 SymbolContext sc; 87 bool first_entry = true; 88 89 FileSpec match_file_spec; 90 uint32_t closest_line_number = UINT32_MAX; 91 92 // Pull out the first entry, and all the others that match its file spec, and stuff them in the tmp list. 93 while (current_idx < sc_list.GetSize()) 94 { 95 bool matches; 96 97 sc_list.GetContextAtIndex (current_idx, sc); 98 if (first_entry) 99 { 100 match_file_spec = sc.line_entry.file; 101 matches = true; 102 first_entry = false; 103 } 104 else 105 matches = (sc.line_entry.file == match_file_spec); 106 107 if (matches) 108 { 109 tmp_sc_list.Append (sc); 110 sc_list.RemoveContextAtIndex(current_idx); 111 112 // ResolveSymbolContext will always return a number that is >= the line number you pass in. 113 // So the smaller line number is always better. 114 if (sc.line_entry.line < closest_line_number) 115 closest_line_number = sc.line_entry.line; 116 } 117 else 118 current_idx++; 119 } 120 121 // Okay, we've found the closest line number match, now throw away all the others, 122 // and make breakpoints out of the closest line number match. 123 124 uint32_t tmp_sc_list_size = tmp_sc_list.GetSize(); 125 126 for (uint32_t i = 0; i < tmp_sc_list_size; i++) 127 { 128 SymbolContext sc; 129 if (tmp_sc_list.GetContextAtIndex(i, sc)) 130 { 131 if (sc.line_entry.line == closest_line_number) 132 { 133 Address line_start = sc.line_entry.range.GetBaseAddress(); 134 if (line_start.IsValid()) 135 { 136 if (filter.AddressPasses(line_start)) 137 { 138 BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(line_start)); 139 if (log && bp_loc_sp && !m_breakpoint->IsInternal()) 140 { 141 StreamString s; 142 bp_loc_sp->GetDescription (&s, lldb::eDescriptionLevelVerbose); 143 log->Printf ("Added location: %s\n", s.GetData()); 144 } 145 } 146 else if (log) 147 { 148 log->Printf ("Breakpoint at file address 0x%llx for %s:%d didn't pass the filter.\n", 149 line_start.GetFileAddress(), 150 m_file_spec.GetFilename().AsCString("<Unknown>"), 151 m_line_number); 152 } 153 } 154 else 155 { 156 if (log) 157 log->Printf ("error: Unable to set breakpoint at file address 0x%llx for %s:%d\n", 158 line_start.GetFileAddress(), 159 m_file_spec.GetFilename().AsCString("<Unknown>"), 160 m_line_number); 161 } 162 } 163 else 164 { 165 #if 0 166 s << "error: Breakpoint at '" << pos->c_str() << "' isn't resolved yet: \n"; 167 if (sc.line_entry.address.Dump(&s, Address::DumpStyleSectionNameOffset)) 168 s.EOL(); 169 if (sc.line_entry.address.Dump(&s, Address::DumpStyleSectionPointerOffset)) 170 s.EOL(); 171 if (sc.line_entry.address.Dump(&s, Address::DumpStyleFileAddress)) 172 s.EOL(); 173 if (sc.line_entry.address.Dump(&s, Address::DumpStyleLoadAddress)) 174 s.EOL(); 175 #endif 176 } 177 } 178 } 179 } 180 181 return Searcher::eCallbackReturnContinue; 182 } 183 184 Searcher::Depth 185 BreakpointResolverFileLine::GetDepth() 186 { 187 return Searcher::eDepthModule; 188 } 189 190 void 191 BreakpointResolverFileLine::GetDescription (Stream *s) 192 { 193 s->Printf ("file ='%s', line = %u", m_file_spec.GetFilename().AsCString(), m_line_number); 194 } 195 196 void 197 BreakpointResolverFileLine::Dump (Stream *s) const 198 { 199 200 } 201 202