130fdc8d8SChris Lattner //===-- BreakpointResolverFileLine.cpp --------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner 
1030fdc8d8SChris Lattner #include "lldb/Breakpoint/BreakpointResolverFileLine.h"
1130fdc8d8SChris Lattner 
1230fdc8d8SChris Lattner // C Includes
1330fdc8d8SChris Lattner // C++ Includes
1430fdc8d8SChris Lattner // Other libraries and framework includes
1530fdc8d8SChris Lattner // Project includes
1630fdc8d8SChris Lattner #include "lldb/Breakpoint/BreakpointLocation.h"
1730fdc8d8SChris Lattner #include "lldb/Core/Log.h"
181f746071SGreg Clayton #include "lldb/Core/Module.h"
1930fdc8d8SChris Lattner #include "lldb/Core/StreamString.h"
201f746071SGreg Clayton #include "lldb/Symbol/CompileUnit.h"
211f746071SGreg Clayton #include "lldb/Symbol/Function.h"
2230fdc8d8SChris Lattner #include "lldb/lldb-private-log.h"
2330fdc8d8SChris Lattner 
2430fdc8d8SChris Lattner using namespace lldb;
2530fdc8d8SChris Lattner using namespace lldb_private;
2630fdc8d8SChris Lattner 
2730fdc8d8SChris Lattner //----------------------------------------------------------------------
2830fdc8d8SChris Lattner // BreakpointResolverFileLine:
2930fdc8d8SChris Lattner //----------------------------------------------------------------------
3030fdc8d8SChris Lattner BreakpointResolverFileLine::BreakpointResolverFileLine
3130fdc8d8SChris Lattner (
3230fdc8d8SChris Lattner     Breakpoint *bkpt,
3330fdc8d8SChris Lattner     const FileSpec &file_spec,
3430fdc8d8SChris Lattner     uint32_t line_no,
35a8558b62SJim Ingham     bool check_inlines,
36a8558b62SJim Ingham     bool skip_prologue
3730fdc8d8SChris Lattner ) :
38b7234e40SJohnny Chen     BreakpointResolver (bkpt, BreakpointResolver::FileLineResolver),
3930fdc8d8SChris Lattner     m_file_spec (file_spec),
4030fdc8d8SChris Lattner     m_line_number (line_no),
41a8558b62SJim Ingham     m_inlines (check_inlines),
42a8558b62SJim Ingham     m_skip_prologue(skip_prologue)
4330fdc8d8SChris Lattner {
4430fdc8d8SChris Lattner }
4530fdc8d8SChris Lattner 
4630fdc8d8SChris Lattner BreakpointResolverFileLine::~BreakpointResolverFileLine ()
4730fdc8d8SChris Lattner {
4830fdc8d8SChris Lattner }
4930fdc8d8SChris Lattner 
5030fdc8d8SChris Lattner Searcher::CallbackReturn
5130fdc8d8SChris Lattner BreakpointResolverFileLine::SearchCallback
5230fdc8d8SChris Lattner (
5330fdc8d8SChris Lattner     SearchFilter &filter,
5430fdc8d8SChris Lattner     SymbolContext &context,
5530fdc8d8SChris Lattner     Address *addr,
5630fdc8d8SChris Lattner     bool containing
5730fdc8d8SChris Lattner )
5830fdc8d8SChris Lattner {
5930fdc8d8SChris Lattner     SymbolContextList sc_list;
6030fdc8d8SChris Lattner 
6130fdc8d8SChris Lattner     assert (m_breakpoint != NULL);
625160ce5cSGreg Clayton     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
6330fdc8d8SChris Lattner 
64bc2f9182SJim Ingham     // There is a tricky bit here.  You can have two compilation units that #include the same file, and
65bc2f9182SJim Ingham     // 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
66bc2f9182SJim Ingham     // other it isn't.  If we considered the CU's independently, then in the second inclusion, we'd move the breakpoint
67bc2f9182SJim Ingham     // to the next function that actually generated code in the header file.  That would end up being confusing.
68bc2f9182SJim Ingham     // So instead, we do the CU iterations by hand here, then scan through the complete list of matches, and figure out
69bc2f9182SJim Ingham     // the closest line number match, and only set breakpoints on that match.
70bc2f9182SJim Ingham 
71bc2f9182SJim Ingham     // Note also that if file_spec only had a file name and not a directory, there may be many different file spec's in
72bc2f9182SJim Ingham     // the resultant list.  The closest line match for one will not be right for some totally different file.
73bc2f9182SJim Ingham     // So we go through the match list and pull out the sets that have the same file spec in their line_entry
74bc2f9182SJim Ingham     // and treat each set separately.
75bc2f9182SJim Ingham 
76c7bece56SGreg Clayton     const size_t num_comp_units = context.module_sp->GetNumCompileUnits();
77c7bece56SGreg Clayton     for (size_t i = 0; i < num_comp_units; i++)
78bc2f9182SJim Ingham     {
79bc2f9182SJim Ingham         CompUnitSP cu_sp (context.module_sp->GetCompileUnitAtIndex (i));
802dafd8edSGreg Clayton         if (cu_sp)
812dafd8edSGreg Clayton         {
822dafd8edSGreg Clayton             if (filter.CompUnitPasses(*cu_sp))
83bc2f9182SJim Ingham                 cu_sp->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, false, eSymbolContextEverything, sc_list);
84bc2f9182SJim Ingham         }
852dafd8edSGreg Clayton     }
86bc2f9182SJim Ingham 
87bc2f9182SJim Ingham     while (sc_list.GetSize() > 0)
88bc2f9182SJim Ingham     {
89bc2f9182SJim Ingham         SymbolContextList tmp_sc_list;
90bc2f9182SJim Ingham         int current_idx = 0;
91bc2f9182SJim Ingham         SymbolContext sc;
92bc2f9182SJim Ingham         bool first_entry = true;
93bc2f9182SJim Ingham 
94bc2f9182SJim Ingham         FileSpec match_file_spec;
95bc2f9182SJim Ingham         uint32_t closest_line_number = UINT32_MAX;
96bc2f9182SJim Ingham 
97bc2f9182SJim Ingham         // Pull out the first entry, and all the others that match its file spec, and stuff them in the tmp list.
98bc2f9182SJim Ingham         while (current_idx < sc_list.GetSize())
99bc2f9182SJim Ingham         {
100bc2f9182SJim Ingham             bool matches;
101bc2f9182SJim Ingham 
102bc2f9182SJim Ingham             sc_list.GetContextAtIndex (current_idx, sc);
103bc2f9182SJim Ingham             if (first_entry)
104bc2f9182SJim Ingham             {
105bc2f9182SJim Ingham                 match_file_spec = sc.line_entry.file;
106bc2f9182SJim Ingham                 matches = true;
107bc2f9182SJim Ingham                 first_entry = false;
108bc2f9182SJim Ingham             }
109bc2f9182SJim Ingham             else
110bc2f9182SJim Ingham                 matches = (sc.line_entry.file == match_file_spec);
111bc2f9182SJim Ingham 
112bc2f9182SJim Ingham             if (matches)
113bc2f9182SJim Ingham             {
114bc2f9182SJim Ingham                 tmp_sc_list.Append (sc);
115bc2f9182SJim Ingham                 sc_list.RemoveContextAtIndex(current_idx);
116bc2f9182SJim Ingham 
117bc2f9182SJim Ingham                 // ResolveSymbolContext will always return a number that is >= the line number you pass in.
118bc2f9182SJim Ingham                 // So the smaller line number is always better.
119bc2f9182SJim Ingham                 if (sc.line_entry.line < closest_line_number)
120bc2f9182SJim Ingham                     closest_line_number = sc.line_entry.line;
121bc2f9182SJim Ingham             }
122bc2f9182SJim Ingham             else
123bc2f9182SJim Ingham                 current_idx++;
124bc2f9182SJim Ingham         }
125bc2f9182SJim Ingham 
1267c06a099SJim Ingham         // Okay, we've found the closest line number match, now throw away all the others:
1277c06a099SJim Ingham 
1287c06a099SJim Ingham         current_idx = 0;
1297c06a099SJim Ingham         while (current_idx < tmp_sc_list.GetSize())
1307c06a099SJim Ingham         {
1317c06a099SJim Ingham             if (tmp_sc_list.GetContextAtIndex(current_idx, sc))
1327c06a099SJim Ingham             {
1337c06a099SJim Ingham                 if (sc.line_entry.line != closest_line_number)
1347c06a099SJim Ingham                     tmp_sc_list.RemoveContextAtIndex(current_idx);
1357c06a099SJim Ingham                 else
1367c06a099SJim Ingham                     current_idx++;
1377c06a099SJim Ingham             }
1387c06a099SJim Ingham         }
1397c06a099SJim Ingham 
1407c06a099SJim Ingham         // Next go through and see if there are line table entries that are contiguous, and if so keep only the
1417c06a099SJim Ingham         // first of the contiguous range:
1427c06a099SJim Ingham 
1437c06a099SJim Ingham         lldb::addr_t last_end_addr = LLDB_INVALID_ADDRESS;
1447c06a099SJim Ingham         current_idx = 0;
1457c06a099SJim Ingham         while (current_idx < tmp_sc_list.GetSize())
1467c06a099SJim Ingham         {
1477c06a099SJim Ingham             if (tmp_sc_list.GetContextAtIndex(current_idx, sc))
1487c06a099SJim Ingham             {
1497c06a099SJim Ingham                 lldb::addr_t start_file_addr = sc.line_entry.range.GetBaseAddress().GetFileAddress();
1507c06a099SJim Ingham                 lldb::addr_t end_file_addr   = start_file_addr + sc.line_entry.range.GetByteSize();
1517c06a099SJim Ingham 
1527c06a099SJim Ingham                 if (start_file_addr == last_end_addr)
1537c06a099SJim Ingham                     tmp_sc_list.RemoveContextAtIndex(current_idx);
1547c06a099SJim Ingham                 else
1557c06a099SJim Ingham                     current_idx++;
1567c06a099SJim Ingham 
1577c06a099SJim Ingham                 last_end_addr = end_file_addr;
1587c06a099SJim Ingham             }
1597c06a099SJim Ingham         }
1607c06a099SJim Ingham 
161bc2f9182SJim Ingham         // and make breakpoints out of the closest line number match.
162bc2f9182SJim Ingham 
163bc2f9182SJim Ingham         uint32_t tmp_sc_list_size = tmp_sc_list.GetSize();
164bc2f9182SJim Ingham 
165bc2f9182SJim Ingham         for (uint32_t i = 0; i < tmp_sc_list_size; i++)
16630fdc8d8SChris Lattner         {
167bc2f9182SJim Ingham             if (tmp_sc_list.GetContextAtIndex(i, sc))
168bc2f9182SJim Ingham             {
16930fdc8d8SChris Lattner                 Address line_start = sc.line_entry.range.GetBaseAddress();
17030fdc8d8SChris Lattner                 if (line_start.IsValid())
17130fdc8d8SChris Lattner                 {
172969795f1SJim Ingham                     if (filter.AddressPasses(line_start))
173969795f1SJim Ingham                     {
174a8558b62SJim Ingham                         // If the line number is before the prologue end, move it there...
175a8558b62SJim Ingham                         bool skipped_prologue = false;
176a8558b62SJim Ingham                         if (m_skip_prologue)
177a8558b62SJim Ingham                         {
178a8558b62SJim Ingham                             if (sc.function)
179a8558b62SJim Ingham                             {
180a8558b62SJim Ingham                                 Address prologue_addr(sc.function->GetAddressRange().GetBaseAddress());
181a8558b62SJim Ingham                                 if (prologue_addr.IsValid() && (line_start == prologue_addr))
182a8558b62SJim Ingham                                 {
183a8558b62SJim Ingham                                     const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
184a8558b62SJim Ingham                                     if (prologue_byte_size)
185a8558b62SJim Ingham                                     {
186a8558b62SJim Ingham                                         prologue_addr.Slide(prologue_byte_size);
187a8558b62SJim Ingham 
188a8558b62SJim Ingham                                         if (filter.AddressPasses(prologue_addr))
189a8558b62SJim Ingham                                         {
190a8558b62SJim Ingham                                             skipped_prologue = true;
191a8558b62SJim Ingham                                             line_start = prologue_addr;
192a8558b62SJim Ingham                                         }
193a8558b62SJim Ingham                                     }
194a8558b62SJim Ingham                                 }
195a8558b62SJim Ingham                             }
196a8558b62SJim Ingham                         }
197a8558b62SJim Ingham 
19830fdc8d8SChris Lattner                         BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(line_start));
19930fdc8d8SChris Lattner                         if (log && bp_loc_sp && !m_breakpoint->IsInternal())
20030fdc8d8SChris Lattner                         {
20130fdc8d8SChris Lattner                             StreamString s;
20230fdc8d8SChris Lattner                             bp_loc_sp->GetDescription (&s, lldb::eDescriptionLevelVerbose);
203a8558b62SJim Ingham                             log->Printf ("Added location (skipped prologue: %s): %s \n", skipped_prologue ? "yes" : "no", s.GetData());
20430fdc8d8SChris Lattner                         }
20530fdc8d8SChris Lattner                     }
206969795f1SJim Ingham                     else if (log)
207969795f1SJim Ingham                     {
208d01b2953SDaniel Malea                         log->Printf ("Breakpoint at file address 0x%" PRIx64 " for %s:%d didn't pass the filter.\n",
209969795f1SJim Ingham                                      line_start.GetFileAddress(),
210969795f1SJim Ingham                                      m_file_spec.GetFilename().AsCString("<Unknown>"),
211969795f1SJim Ingham                                      m_line_number);
212969795f1SJim Ingham                     }
213969795f1SJim Ingham                 }
21430fdc8d8SChris Lattner                 else
21530fdc8d8SChris Lattner                 {
21630fdc8d8SChris Lattner                     if (log)
217d01b2953SDaniel Malea                         log->Printf ("error: Unable to set breakpoint at file address 0x%" PRIx64 " for %s:%d\n",
21830fdc8d8SChris Lattner                                      line_start.GetFileAddress(),
21930fdc8d8SChris Lattner                                      m_file_spec.GetFilename().AsCString("<Unknown>"),
22030fdc8d8SChris Lattner                                      m_line_number);
22130fdc8d8SChris Lattner                 }
22230fdc8d8SChris Lattner             }
223bc2f9182SJim Ingham         }
224bc2f9182SJim Ingham     }
225bc2f9182SJim Ingham 
22630fdc8d8SChris Lattner     return Searcher::eCallbackReturnContinue;
22730fdc8d8SChris Lattner }
22830fdc8d8SChris Lattner 
22930fdc8d8SChris Lattner Searcher::Depth
23030fdc8d8SChris Lattner BreakpointResolverFileLine::GetDepth()
23130fdc8d8SChris Lattner {
232bc2f9182SJim Ingham     return Searcher::eDepthModule;
23330fdc8d8SChris Lattner }
23430fdc8d8SChris Lattner 
23530fdc8d8SChris Lattner void
23630fdc8d8SChris Lattner BreakpointResolverFileLine::GetDescription (Stream *s)
23730fdc8d8SChris Lattner {
238*405fab90SGreg Clayton     s->Printf ("file = '%s', line = %u", m_file_spec.GetPath().c_str(), m_line_number);
23930fdc8d8SChris Lattner }
24030fdc8d8SChris Lattner 
24130fdc8d8SChris Lattner void
24230fdc8d8SChris Lattner BreakpointResolverFileLine::Dump (Stream *s) const
24330fdc8d8SChris Lattner {
24430fdc8d8SChris Lattner 
24530fdc8d8SChris Lattner }
24630fdc8d8SChris Lattner 
247