15ffd83dbSDimitry Andric //===-- CommandObjectSource.cpp -------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "CommandObjectSource.h"
10*0b57cec5SDimitry Andric 
11*0b57cec5SDimitry Andric #include "lldb/Core/Debugger.h"
12*0b57cec5SDimitry Andric #include "lldb/Core/FileLineResolver.h"
13*0b57cec5SDimitry Andric #include "lldb/Core/Module.h"
14*0b57cec5SDimitry Andric #include "lldb/Core/ModuleSpec.h"
15*0b57cec5SDimitry Andric #include "lldb/Core/SourceManager.h"
16*0b57cec5SDimitry Andric #include "lldb/Host/OptionParser.h"
17*0b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
18*0b57cec5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
19*0b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h"
20*0b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h"
21*0b57cec5SDimitry Andric #include "lldb/Symbol/Function.h"
22*0b57cec5SDimitry Andric #include "lldb/Symbol/Symbol.h"
23*0b57cec5SDimitry Andric #include "lldb/Target/SectionLoadList.h"
24*0b57cec5SDimitry Andric #include "lldb/Target/StackFrame.h"
25*0b57cec5SDimitry Andric #include "lldb/Utility/FileSpec.h"
26*0b57cec5SDimitry Andric 
27*0b57cec5SDimitry Andric using namespace lldb;
28*0b57cec5SDimitry Andric using namespace lldb_private;
29*0b57cec5SDimitry Andric 
30*0b57cec5SDimitry Andric #pragma mark CommandObjectSourceInfo
31*0b57cec5SDimitry Andric // CommandObjectSourceInfo - debug line entries dumping command
329dba64beSDimitry Andric #define LLDB_OPTIONS_source_info
339dba64beSDimitry Andric #include "CommandOptions.inc"
34*0b57cec5SDimitry Andric 
35*0b57cec5SDimitry Andric class CommandObjectSourceInfo : public CommandObjectParsed {
36*0b57cec5SDimitry Andric   class CommandOptions : public Options {
37*0b57cec5SDimitry Andric   public:
38*0b57cec5SDimitry Andric     CommandOptions() : Options() {}
39*0b57cec5SDimitry Andric 
40*0b57cec5SDimitry Andric     ~CommandOptions() override = default;
41*0b57cec5SDimitry Andric 
42*0b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
43*0b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
44*0b57cec5SDimitry Andric       Status error;
45*0b57cec5SDimitry Andric       const int short_option = GetDefinitions()[option_idx].short_option;
46*0b57cec5SDimitry Andric       switch (short_option) {
47*0b57cec5SDimitry Andric       case 'l':
48*0b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, start_line))
49*0b57cec5SDimitry Andric           error.SetErrorStringWithFormat("invalid line number: '%s'",
50*0b57cec5SDimitry Andric                                          option_arg.str().c_str());
51*0b57cec5SDimitry Andric         break;
52*0b57cec5SDimitry Andric 
53*0b57cec5SDimitry Andric       case 'e':
54*0b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, end_line))
55*0b57cec5SDimitry Andric           error.SetErrorStringWithFormat("invalid line number: '%s'",
56*0b57cec5SDimitry Andric                                          option_arg.str().c_str());
57*0b57cec5SDimitry Andric         break;
58*0b57cec5SDimitry Andric 
59*0b57cec5SDimitry Andric       case 'c':
60*0b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, num_lines))
61*0b57cec5SDimitry Andric           error.SetErrorStringWithFormat("invalid line count: '%s'",
62*0b57cec5SDimitry Andric                                          option_arg.str().c_str());
63*0b57cec5SDimitry Andric         break;
64*0b57cec5SDimitry Andric 
65*0b57cec5SDimitry Andric       case 'f':
665ffd83dbSDimitry Andric         file_name = std::string(option_arg);
67*0b57cec5SDimitry Andric         break;
68*0b57cec5SDimitry Andric 
69*0b57cec5SDimitry Andric       case 'n':
705ffd83dbSDimitry Andric         symbol_name = std::string(option_arg);
71*0b57cec5SDimitry Andric         break;
72*0b57cec5SDimitry Andric 
73*0b57cec5SDimitry Andric       case 'a': {
74*0b57cec5SDimitry Andric         address = OptionArgParser::ToAddress(execution_context, option_arg,
75*0b57cec5SDimitry Andric                                              LLDB_INVALID_ADDRESS, &error);
76*0b57cec5SDimitry Andric       } break;
77*0b57cec5SDimitry Andric       case 's':
78*0b57cec5SDimitry Andric         modules.push_back(std::string(option_arg));
79*0b57cec5SDimitry Andric         break;
80*0b57cec5SDimitry Andric       default:
819dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
82*0b57cec5SDimitry Andric       }
83*0b57cec5SDimitry Andric 
84*0b57cec5SDimitry Andric       return error;
85*0b57cec5SDimitry Andric     }
86*0b57cec5SDimitry Andric 
87*0b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
88*0b57cec5SDimitry Andric       file_spec.Clear();
89*0b57cec5SDimitry Andric       file_name.clear();
90*0b57cec5SDimitry Andric       symbol_name.clear();
91*0b57cec5SDimitry Andric       address = LLDB_INVALID_ADDRESS;
92*0b57cec5SDimitry Andric       start_line = 0;
93*0b57cec5SDimitry Andric       end_line = 0;
94*0b57cec5SDimitry Andric       num_lines = 0;
95*0b57cec5SDimitry Andric       modules.clear();
96*0b57cec5SDimitry Andric     }
97*0b57cec5SDimitry Andric 
98*0b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
99*0b57cec5SDimitry Andric       return llvm::makeArrayRef(g_source_info_options);
100*0b57cec5SDimitry Andric     }
101*0b57cec5SDimitry Andric 
102*0b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
103*0b57cec5SDimitry Andric     FileSpec file_spec;
104*0b57cec5SDimitry Andric     std::string file_name;
105*0b57cec5SDimitry Andric     std::string symbol_name;
106*0b57cec5SDimitry Andric     lldb::addr_t address;
107*0b57cec5SDimitry Andric     uint32_t start_line;
108*0b57cec5SDimitry Andric     uint32_t end_line;
109*0b57cec5SDimitry Andric     uint32_t num_lines;
110480093f4SDimitry Andric     std::vector<std::string> modules;
111*0b57cec5SDimitry Andric   };
112*0b57cec5SDimitry Andric 
113*0b57cec5SDimitry Andric public:
114*0b57cec5SDimitry Andric   CommandObjectSourceInfo(CommandInterpreter &interpreter)
115*0b57cec5SDimitry Andric       : CommandObjectParsed(
116*0b57cec5SDimitry Andric             interpreter, "source info",
117*0b57cec5SDimitry Andric             "Display source line information for the current target "
118*0b57cec5SDimitry Andric             "process.  Defaults to instruction pointer in current stack "
119*0b57cec5SDimitry Andric             "frame.",
120*0b57cec5SDimitry Andric             nullptr, eCommandRequiresTarget),
121*0b57cec5SDimitry Andric         m_options() {}
122*0b57cec5SDimitry Andric 
123*0b57cec5SDimitry Andric   ~CommandObjectSourceInfo() override = default;
124*0b57cec5SDimitry Andric 
125*0b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
126*0b57cec5SDimitry Andric 
127*0b57cec5SDimitry Andric protected:
128*0b57cec5SDimitry Andric   // Dump the line entries in each symbol context. Return the number of entries
129*0b57cec5SDimitry Andric   // found. If module_list is set, only dump lines contained in one of the
130*0b57cec5SDimitry Andric   // modules. If file_spec is set, only dump lines in the file. If the
131*0b57cec5SDimitry Andric   // start_line option was specified, don't print lines less than start_line.
132*0b57cec5SDimitry Andric   // If the end_line option was specified, don't print lines greater than
133*0b57cec5SDimitry Andric   // end_line. If the num_lines option was specified, dont print more than
134*0b57cec5SDimitry Andric   // num_lines entries.
135*0b57cec5SDimitry Andric   uint32_t DumpLinesInSymbolContexts(Stream &strm,
136*0b57cec5SDimitry Andric                                      const SymbolContextList &sc_list,
137*0b57cec5SDimitry Andric                                      const ModuleList &module_list,
138*0b57cec5SDimitry Andric                                      const FileSpec &file_spec) {
139*0b57cec5SDimitry Andric     uint32_t start_line = m_options.start_line;
140*0b57cec5SDimitry Andric     uint32_t end_line = m_options.end_line;
141*0b57cec5SDimitry Andric     uint32_t num_lines = m_options.num_lines;
142*0b57cec5SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
143*0b57cec5SDimitry Andric 
144*0b57cec5SDimitry Andric     uint32_t num_matches = 0;
145*0b57cec5SDimitry Andric     // Dump all the line entries for the file in the list.
146*0b57cec5SDimitry Andric     ConstString last_module_file_name;
147*0b57cec5SDimitry Andric     uint32_t num_scs = sc_list.GetSize();
148*0b57cec5SDimitry Andric     for (uint32_t i = 0; i < num_scs; ++i) {
149*0b57cec5SDimitry Andric       SymbolContext sc;
150*0b57cec5SDimitry Andric       sc_list.GetContextAtIndex(i, sc);
151*0b57cec5SDimitry Andric       if (sc.comp_unit) {
152*0b57cec5SDimitry Andric         Module *module = sc.module_sp.get();
153*0b57cec5SDimitry Andric         CompileUnit *cu = sc.comp_unit;
154*0b57cec5SDimitry Andric         const LineEntry &line_entry = sc.line_entry;
155*0b57cec5SDimitry Andric         assert(module && cu);
156*0b57cec5SDimitry Andric 
157*0b57cec5SDimitry Andric         // Are we looking for specific modules, files or lines?
158*0b57cec5SDimitry Andric         if (module_list.GetSize() &&
159*0b57cec5SDimitry Andric             module_list.GetIndexForModule(module) == LLDB_INVALID_INDEX32)
160*0b57cec5SDimitry Andric           continue;
161480093f4SDimitry Andric         if (!FileSpec::Match(file_spec, line_entry.file))
162*0b57cec5SDimitry Andric           continue;
163*0b57cec5SDimitry Andric         if (start_line > 0 && line_entry.line < start_line)
164*0b57cec5SDimitry Andric           continue;
165*0b57cec5SDimitry Andric         if (end_line > 0 && line_entry.line > end_line)
166*0b57cec5SDimitry Andric           continue;
167*0b57cec5SDimitry Andric         if (num_lines > 0 && num_matches > num_lines)
168*0b57cec5SDimitry Andric           continue;
169*0b57cec5SDimitry Andric 
170*0b57cec5SDimitry Andric         // Print a new header if the module changed.
171480093f4SDimitry Andric         ConstString module_file_name = module->GetFileSpec().GetFilename();
172*0b57cec5SDimitry Andric         assert(module_file_name);
173*0b57cec5SDimitry Andric         if (module_file_name != last_module_file_name) {
174*0b57cec5SDimitry Andric           if (num_matches > 0)
175*0b57cec5SDimitry Andric             strm << "\n\n";
176*0b57cec5SDimitry Andric           strm << "Lines found in module `" << module_file_name << "\n";
177*0b57cec5SDimitry Andric         }
178*0b57cec5SDimitry Andric         // Dump the line entry.
179*0b57cec5SDimitry Andric         line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu,
180*0b57cec5SDimitry Andric                                   target, /*show_address_only=*/false);
181*0b57cec5SDimitry Andric         strm << "\n";
182*0b57cec5SDimitry Andric         last_module_file_name = module_file_name;
183*0b57cec5SDimitry Andric         num_matches++;
184*0b57cec5SDimitry Andric       }
185*0b57cec5SDimitry Andric     }
186*0b57cec5SDimitry Andric     return num_matches;
187*0b57cec5SDimitry Andric   }
188*0b57cec5SDimitry Andric 
189*0b57cec5SDimitry Andric   // Dump the requested line entries for the file in the compilation unit.
190*0b57cec5SDimitry Andric   // Return the number of entries found. If module_list is set, only dump lines
191*0b57cec5SDimitry Andric   // contained in one of the modules. If the start_line option was specified,
192*0b57cec5SDimitry Andric   // don't print lines less than start_line. If the end_line option was
193*0b57cec5SDimitry Andric   // specified, don't print lines greater than end_line. If the num_lines
194*0b57cec5SDimitry Andric   // option was specified, dont print more than num_lines entries.
195*0b57cec5SDimitry Andric   uint32_t DumpFileLinesInCompUnit(Stream &strm, Module *module,
196*0b57cec5SDimitry Andric                                    CompileUnit *cu, const FileSpec &file_spec) {
197*0b57cec5SDimitry Andric     uint32_t start_line = m_options.start_line;
198*0b57cec5SDimitry Andric     uint32_t end_line = m_options.end_line;
199*0b57cec5SDimitry Andric     uint32_t num_lines = m_options.num_lines;
200*0b57cec5SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
201*0b57cec5SDimitry Andric 
202*0b57cec5SDimitry Andric     uint32_t num_matches = 0;
203*0b57cec5SDimitry Andric     assert(module);
204*0b57cec5SDimitry Andric     if (cu) {
205*0b57cec5SDimitry Andric       assert(file_spec.GetFilename().AsCString());
206*0b57cec5SDimitry Andric       bool has_path = (file_spec.GetDirectory().AsCString() != nullptr);
207*0b57cec5SDimitry Andric       const FileSpecList &cu_file_list = cu->GetSupportFiles();
208*0b57cec5SDimitry Andric       size_t file_idx = cu_file_list.FindFileIndex(0, file_spec, has_path);
209*0b57cec5SDimitry Andric       if (file_idx != UINT32_MAX) {
210*0b57cec5SDimitry Andric         // Update the file to how it appears in the CU.
211*0b57cec5SDimitry Andric         const FileSpec &cu_file_spec =
212*0b57cec5SDimitry Andric             cu_file_list.GetFileSpecAtIndex(file_idx);
213*0b57cec5SDimitry Andric 
214*0b57cec5SDimitry Andric         // Dump all matching lines at or above start_line for the file in the
215*0b57cec5SDimitry Andric         // CU.
216*0b57cec5SDimitry Andric         ConstString file_spec_name = file_spec.GetFilename();
217480093f4SDimitry Andric         ConstString module_file_name = module->GetFileSpec().GetFilename();
218*0b57cec5SDimitry Andric         bool cu_header_printed = false;
219*0b57cec5SDimitry Andric         uint32_t line = start_line;
220*0b57cec5SDimitry Andric         while (true) {
221*0b57cec5SDimitry Andric           LineEntry line_entry;
222*0b57cec5SDimitry Andric 
223*0b57cec5SDimitry Andric           // Find the lowest index of a line entry with a line equal to or
224*0b57cec5SDimitry Andric           // higher than 'line'.
225*0b57cec5SDimitry Andric           uint32_t start_idx = 0;
226*0b57cec5SDimitry Andric           start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec,
227*0b57cec5SDimitry Andric                                         /*exact=*/false, &line_entry);
228*0b57cec5SDimitry Andric           if (start_idx == UINT32_MAX)
229*0b57cec5SDimitry Andric             // No more line entries for our file in this CU.
230*0b57cec5SDimitry Andric             break;
231*0b57cec5SDimitry Andric 
232*0b57cec5SDimitry Andric           if (end_line > 0 && line_entry.line > end_line)
233*0b57cec5SDimitry Andric             break;
234*0b57cec5SDimitry Andric 
235*0b57cec5SDimitry Andric           // Loop through to find any other entries for this line, dumping
236*0b57cec5SDimitry Andric           // each.
237*0b57cec5SDimitry Andric           line = line_entry.line;
238*0b57cec5SDimitry Andric           do {
239*0b57cec5SDimitry Andric             num_matches++;
240*0b57cec5SDimitry Andric             if (num_lines > 0 && num_matches > num_lines)
241*0b57cec5SDimitry Andric               break;
242480093f4SDimitry Andric             assert(cu_file_spec == line_entry.file);
243*0b57cec5SDimitry Andric             if (!cu_header_printed) {
244*0b57cec5SDimitry Andric               if (num_matches > 0)
245*0b57cec5SDimitry Andric                 strm << "\n\n";
246*0b57cec5SDimitry Andric               strm << "Lines found for file " << file_spec_name
247480093f4SDimitry Andric                    << " in compilation unit "
248480093f4SDimitry Andric                    << cu->GetPrimaryFile().GetFilename() << " in `"
249*0b57cec5SDimitry Andric                    << module_file_name << "\n";
250*0b57cec5SDimitry Andric               cu_header_printed = true;
251*0b57cec5SDimitry Andric             }
252*0b57cec5SDimitry Andric             line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu,
253*0b57cec5SDimitry Andric                                       target, /*show_address_only=*/false);
254*0b57cec5SDimitry Andric             strm << "\n";
255*0b57cec5SDimitry Andric 
256*0b57cec5SDimitry Andric             // Anymore after this one?
257*0b57cec5SDimitry Andric             start_idx++;
258*0b57cec5SDimitry Andric             start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec,
259*0b57cec5SDimitry Andric                                           /*exact=*/true, &line_entry);
260*0b57cec5SDimitry Andric           } while (start_idx != UINT32_MAX);
261*0b57cec5SDimitry Andric 
262*0b57cec5SDimitry Andric           // Try the next higher line, starting over at start_idx 0.
263*0b57cec5SDimitry Andric           line++;
264*0b57cec5SDimitry Andric         }
265*0b57cec5SDimitry Andric       }
266*0b57cec5SDimitry Andric     }
267*0b57cec5SDimitry Andric     return num_matches;
268*0b57cec5SDimitry Andric   }
269*0b57cec5SDimitry Andric 
270*0b57cec5SDimitry Andric   // Dump the requested line entries for the file in the module. Return the
271*0b57cec5SDimitry Andric   // number of entries found. If module_list is set, only dump lines contained
272*0b57cec5SDimitry Andric   // in one of the modules. If the start_line option was specified, don't print
273*0b57cec5SDimitry Andric   // lines less than start_line. If the end_line option was specified, don't
274*0b57cec5SDimitry Andric   // print lines greater than end_line. If the num_lines option was specified,
275*0b57cec5SDimitry Andric   // dont print more than num_lines entries.
276*0b57cec5SDimitry Andric   uint32_t DumpFileLinesInModule(Stream &strm, Module *module,
277*0b57cec5SDimitry Andric                                  const FileSpec &file_spec) {
278*0b57cec5SDimitry Andric     uint32_t num_matches = 0;
279*0b57cec5SDimitry Andric     if (module) {
280*0b57cec5SDimitry Andric       // Look through all the compilation units (CUs) in this module for ones
281*0b57cec5SDimitry Andric       // that contain lines of code from this source file.
282*0b57cec5SDimitry Andric       for (size_t i = 0; i < module->GetNumCompileUnits(); i++) {
283*0b57cec5SDimitry Andric         // Look for a matching source file in this CU.
284*0b57cec5SDimitry Andric         CompUnitSP cu_sp(module->GetCompileUnitAtIndex(i));
285*0b57cec5SDimitry Andric         if (cu_sp) {
286*0b57cec5SDimitry Andric           num_matches +=
287*0b57cec5SDimitry Andric               DumpFileLinesInCompUnit(strm, module, cu_sp.get(), file_spec);
288*0b57cec5SDimitry Andric         }
289*0b57cec5SDimitry Andric       }
290*0b57cec5SDimitry Andric     }
291*0b57cec5SDimitry Andric     return num_matches;
292*0b57cec5SDimitry Andric   }
293*0b57cec5SDimitry Andric 
294*0b57cec5SDimitry Andric   // Given an address and a list of modules, append the symbol contexts of all
295*0b57cec5SDimitry Andric   // line entries containing the address found in the modules and return the
296*0b57cec5SDimitry Andric   // count of matches.  If none is found, return an error in 'error_strm'.
297*0b57cec5SDimitry Andric   size_t GetSymbolContextsForAddress(const ModuleList &module_list,
298*0b57cec5SDimitry Andric                                      lldb::addr_t addr,
299*0b57cec5SDimitry Andric                                      SymbolContextList &sc_list,
300*0b57cec5SDimitry Andric                                      StreamString &error_strm) {
301*0b57cec5SDimitry Andric     Address so_addr;
302*0b57cec5SDimitry Andric     size_t num_matches = 0;
303*0b57cec5SDimitry Andric     assert(module_list.GetSize() > 0);
304*0b57cec5SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
305*0b57cec5SDimitry Andric     if (target->GetSectionLoadList().IsEmpty()) {
306*0b57cec5SDimitry Andric       // The target isn't loaded yet, we need to lookup the file address in all
307*0b57cec5SDimitry Andric       // modules.  Note: the module list option does not apply to addresses.
308*0b57cec5SDimitry Andric       const size_t num_modules = module_list.GetSize();
309*0b57cec5SDimitry Andric       for (size_t i = 0; i < num_modules; ++i) {
310*0b57cec5SDimitry Andric         ModuleSP module_sp(module_list.GetModuleAtIndex(i));
311*0b57cec5SDimitry Andric         if (!module_sp)
312*0b57cec5SDimitry Andric           continue;
313*0b57cec5SDimitry Andric         if (module_sp->ResolveFileAddress(addr, so_addr)) {
314*0b57cec5SDimitry Andric           SymbolContext sc;
315*0b57cec5SDimitry Andric           sc.Clear(true);
316*0b57cec5SDimitry Andric           if (module_sp->ResolveSymbolContextForAddress(
317*0b57cec5SDimitry Andric                   so_addr, eSymbolContextEverything, sc) &
318*0b57cec5SDimitry Andric               eSymbolContextLineEntry) {
319*0b57cec5SDimitry Andric             sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false);
320*0b57cec5SDimitry Andric             ++num_matches;
321*0b57cec5SDimitry Andric           }
322*0b57cec5SDimitry Andric         }
323*0b57cec5SDimitry Andric       }
324*0b57cec5SDimitry Andric       if (num_matches == 0)
325*0b57cec5SDimitry Andric         error_strm.Printf("Source information for file address 0x%" PRIx64
326*0b57cec5SDimitry Andric                           " not found in any modules.\n",
327*0b57cec5SDimitry Andric                           addr);
328*0b57cec5SDimitry Andric     } else {
329*0b57cec5SDimitry Andric       // The target has some things loaded, resolve this address to a compile
330*0b57cec5SDimitry Andric       // unit + file + line and display
331*0b57cec5SDimitry Andric       if (target->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) {
332*0b57cec5SDimitry Andric         ModuleSP module_sp(so_addr.GetModule());
333*0b57cec5SDimitry Andric         // Check to make sure this module is in our list.
334480093f4SDimitry Andric         if (module_sp && module_list.GetIndexForModule(module_sp.get()) !=
335*0b57cec5SDimitry Andric                              LLDB_INVALID_INDEX32) {
336*0b57cec5SDimitry Andric           SymbolContext sc;
337*0b57cec5SDimitry Andric           sc.Clear(true);
338*0b57cec5SDimitry Andric           if (module_sp->ResolveSymbolContextForAddress(
339*0b57cec5SDimitry Andric                   so_addr, eSymbolContextEverything, sc) &
340*0b57cec5SDimitry Andric               eSymbolContextLineEntry) {
341*0b57cec5SDimitry Andric             sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false);
342*0b57cec5SDimitry Andric             ++num_matches;
343*0b57cec5SDimitry Andric           } else {
344*0b57cec5SDimitry Andric             StreamString addr_strm;
345*0b57cec5SDimitry Andric             so_addr.Dump(&addr_strm, nullptr,
346*0b57cec5SDimitry Andric                          Address::DumpStyleModuleWithFileAddress);
347*0b57cec5SDimitry Andric             error_strm.Printf(
348*0b57cec5SDimitry Andric                 "Address 0x%" PRIx64 " resolves to %s, but there is"
349*0b57cec5SDimitry Andric                 " no source information available for this address.\n",
350*0b57cec5SDimitry Andric                 addr, addr_strm.GetData());
351*0b57cec5SDimitry Andric           }
352*0b57cec5SDimitry Andric         } else {
353*0b57cec5SDimitry Andric           StreamString addr_strm;
354*0b57cec5SDimitry Andric           so_addr.Dump(&addr_strm, nullptr,
355*0b57cec5SDimitry Andric                        Address::DumpStyleModuleWithFileAddress);
356*0b57cec5SDimitry Andric           error_strm.Printf("Address 0x%" PRIx64
357*0b57cec5SDimitry Andric                             " resolves to %s, but it cannot"
358*0b57cec5SDimitry Andric                             " be found in any modules.\n",
359*0b57cec5SDimitry Andric                             addr, addr_strm.GetData());
360*0b57cec5SDimitry Andric         }
361*0b57cec5SDimitry Andric       } else
362*0b57cec5SDimitry Andric         error_strm.Printf("Unable to resolve address 0x%" PRIx64 ".\n", addr);
363*0b57cec5SDimitry Andric     }
364*0b57cec5SDimitry Andric     return num_matches;
365*0b57cec5SDimitry Andric   }
366*0b57cec5SDimitry Andric 
367*0b57cec5SDimitry Andric   // Dump the line entries found in functions matching the name specified in
368*0b57cec5SDimitry Andric   // the option.
369*0b57cec5SDimitry Andric   bool DumpLinesInFunctions(CommandReturnObject &result) {
370*0b57cec5SDimitry Andric     SymbolContextList sc_list_funcs;
371*0b57cec5SDimitry Andric     ConstString name(m_options.symbol_name.c_str());
372*0b57cec5SDimitry Andric     SymbolContextList sc_list_lines;
373*0b57cec5SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
374*0b57cec5SDimitry Andric     uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
375*0b57cec5SDimitry Andric 
376*0b57cec5SDimitry Andric     // Note: module_list can't be const& because FindFunctionSymbols isn't
377*0b57cec5SDimitry Andric     // const.
378*0b57cec5SDimitry Andric     ModuleList module_list =
379*0b57cec5SDimitry Andric         (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages();
380*0b57cec5SDimitry Andric     module_list.FindFunctions(name, eFunctionNameTypeAuto,
381*0b57cec5SDimitry Andric                               /*include_symbols=*/false,
3829dba64beSDimitry Andric                               /*include_inlines=*/true, sc_list_funcs);
3839dba64beSDimitry Andric     size_t num_matches = sc_list_funcs.GetSize();
3849dba64beSDimitry Andric 
385*0b57cec5SDimitry Andric     if (!num_matches) {
386*0b57cec5SDimitry Andric       // If we didn't find any functions with that name, try searching for
387*0b57cec5SDimitry Andric       // symbols that line up exactly with function addresses.
388*0b57cec5SDimitry Andric       SymbolContextList sc_list_symbols;
389480093f4SDimitry Andric       module_list.FindFunctionSymbols(name, eFunctionNameTypeAuto,
390480093f4SDimitry Andric                                       sc_list_symbols);
3919dba64beSDimitry Andric       size_t num_symbol_matches = sc_list_symbols.GetSize();
392*0b57cec5SDimitry Andric       for (size_t i = 0; i < num_symbol_matches; i++) {
393*0b57cec5SDimitry Andric         SymbolContext sc;
394*0b57cec5SDimitry Andric         sc_list_symbols.GetContextAtIndex(i, sc);
395*0b57cec5SDimitry Andric         if (sc.symbol && sc.symbol->ValueIsAddress()) {
396*0b57cec5SDimitry Andric           const Address &base_address = sc.symbol->GetAddressRef();
397*0b57cec5SDimitry Andric           Function *function = base_address.CalculateSymbolContextFunction();
398*0b57cec5SDimitry Andric           if (function) {
399*0b57cec5SDimitry Andric             sc_list_funcs.Append(SymbolContext(function));
400*0b57cec5SDimitry Andric             num_matches++;
401*0b57cec5SDimitry Andric           }
402*0b57cec5SDimitry Andric         }
403*0b57cec5SDimitry Andric       }
404*0b57cec5SDimitry Andric     }
405*0b57cec5SDimitry Andric     if (num_matches == 0) {
406*0b57cec5SDimitry Andric       result.AppendErrorWithFormat("Could not find function named \'%s\'.\n",
407*0b57cec5SDimitry Andric                                    m_options.symbol_name.c_str());
408*0b57cec5SDimitry Andric       return false;
409*0b57cec5SDimitry Andric     }
410*0b57cec5SDimitry Andric     for (size_t i = 0; i < num_matches; i++) {
411*0b57cec5SDimitry Andric       SymbolContext sc;
412*0b57cec5SDimitry Andric       sc_list_funcs.GetContextAtIndex(i, sc);
413*0b57cec5SDimitry Andric       bool context_found_for_symbol = false;
414*0b57cec5SDimitry Andric       // Loop through all the ranges in the function.
415*0b57cec5SDimitry Andric       AddressRange range;
416*0b57cec5SDimitry Andric       for (uint32_t r = 0;
417*0b57cec5SDimitry Andric            sc.GetAddressRange(eSymbolContextEverything, r,
418*0b57cec5SDimitry Andric                               /*use_inline_block_range=*/true, range);
419*0b57cec5SDimitry Andric            ++r) {
420*0b57cec5SDimitry Andric         // Append the symbol contexts for each address in the range to
421*0b57cec5SDimitry Andric         // sc_list_lines.
422*0b57cec5SDimitry Andric         const Address &base_address = range.GetBaseAddress();
423*0b57cec5SDimitry Andric         const addr_t size = range.GetByteSize();
424*0b57cec5SDimitry Andric         lldb::addr_t start_addr = base_address.GetLoadAddress(target);
425*0b57cec5SDimitry Andric         if (start_addr == LLDB_INVALID_ADDRESS)
426*0b57cec5SDimitry Andric           start_addr = base_address.GetFileAddress();
427*0b57cec5SDimitry Andric         lldb::addr_t end_addr = start_addr + size;
428*0b57cec5SDimitry Andric         for (lldb::addr_t addr = start_addr; addr < end_addr;
429*0b57cec5SDimitry Andric              addr += addr_byte_size) {
430*0b57cec5SDimitry Andric           StreamString error_strm;
431*0b57cec5SDimitry Andric           if (!GetSymbolContextsForAddress(module_list, addr, sc_list_lines,
432*0b57cec5SDimitry Andric                                            error_strm))
433*0b57cec5SDimitry Andric             result.AppendWarningWithFormat("in symbol '%s': %s",
434*0b57cec5SDimitry Andric                                            sc.GetFunctionName().AsCString(),
435*0b57cec5SDimitry Andric                                            error_strm.GetData());
436*0b57cec5SDimitry Andric           else
437*0b57cec5SDimitry Andric             context_found_for_symbol = true;
438*0b57cec5SDimitry Andric         }
439*0b57cec5SDimitry Andric       }
440*0b57cec5SDimitry Andric       if (!context_found_for_symbol)
441*0b57cec5SDimitry Andric         result.AppendWarningWithFormat("Unable to find line information"
442*0b57cec5SDimitry Andric                                        " for matching symbol '%s'.\n",
443*0b57cec5SDimitry Andric                                        sc.GetFunctionName().AsCString());
444*0b57cec5SDimitry Andric     }
445*0b57cec5SDimitry Andric     if (sc_list_lines.GetSize() == 0) {
446*0b57cec5SDimitry Andric       result.AppendErrorWithFormat("No line information could be found"
447*0b57cec5SDimitry Andric                                    " for any symbols matching '%s'.\n",
448*0b57cec5SDimitry Andric                                    name.AsCString());
449*0b57cec5SDimitry Andric       return false;
450*0b57cec5SDimitry Andric     }
451*0b57cec5SDimitry Andric     FileSpec file_spec;
452*0b57cec5SDimitry Andric     if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list_lines,
453*0b57cec5SDimitry Andric                                    module_list, file_spec)) {
454*0b57cec5SDimitry Andric       result.AppendErrorWithFormat(
455*0b57cec5SDimitry Andric           "Unable to dump line information for symbol '%s'.\n",
456*0b57cec5SDimitry Andric           name.AsCString());
457*0b57cec5SDimitry Andric       return false;
458*0b57cec5SDimitry Andric     }
459*0b57cec5SDimitry Andric     return true;
460*0b57cec5SDimitry Andric   }
461*0b57cec5SDimitry Andric 
462*0b57cec5SDimitry Andric   // Dump the line entries found for the address specified in the option.
463*0b57cec5SDimitry Andric   bool DumpLinesForAddress(CommandReturnObject &result) {
464*0b57cec5SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
465*0b57cec5SDimitry Andric     SymbolContextList sc_list;
466*0b57cec5SDimitry Andric 
467*0b57cec5SDimitry Andric     StreamString error_strm;
468*0b57cec5SDimitry Andric     if (!GetSymbolContextsForAddress(target->GetImages(), m_options.address,
469*0b57cec5SDimitry Andric                                      sc_list, error_strm)) {
470*0b57cec5SDimitry Andric       result.AppendErrorWithFormat("%s.\n", error_strm.GetData());
471*0b57cec5SDimitry Andric       return false;
472*0b57cec5SDimitry Andric     }
473*0b57cec5SDimitry Andric     ModuleList module_list;
474*0b57cec5SDimitry Andric     FileSpec file_spec;
475*0b57cec5SDimitry Andric     if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list,
476*0b57cec5SDimitry Andric                                    module_list, file_spec)) {
477*0b57cec5SDimitry Andric       result.AppendErrorWithFormat("No modules contain load address 0x%" PRIx64
478*0b57cec5SDimitry Andric                                    ".\n",
479*0b57cec5SDimitry Andric                                    m_options.address);
480*0b57cec5SDimitry Andric       return false;
481*0b57cec5SDimitry Andric     }
482*0b57cec5SDimitry Andric     return true;
483*0b57cec5SDimitry Andric   }
484*0b57cec5SDimitry Andric 
485*0b57cec5SDimitry Andric   // Dump the line entries found in the file specified in the option.
486*0b57cec5SDimitry Andric   bool DumpLinesForFile(CommandReturnObject &result) {
487*0b57cec5SDimitry Andric     FileSpec file_spec(m_options.file_name);
488*0b57cec5SDimitry Andric     const char *filename = m_options.file_name.c_str();
489*0b57cec5SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
490*0b57cec5SDimitry Andric     const ModuleList &module_list =
491*0b57cec5SDimitry Andric         (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages();
492*0b57cec5SDimitry Andric 
493*0b57cec5SDimitry Andric     bool displayed_something = false;
494*0b57cec5SDimitry Andric     const size_t num_modules = module_list.GetSize();
495*0b57cec5SDimitry Andric     for (uint32_t i = 0; i < num_modules; ++i) {
496*0b57cec5SDimitry Andric       // Dump lines for this module.
497*0b57cec5SDimitry Andric       Module *module = module_list.GetModulePointerAtIndex(i);
498*0b57cec5SDimitry Andric       assert(module);
499*0b57cec5SDimitry Andric       if (DumpFileLinesInModule(result.GetOutputStream(), module, file_spec))
500*0b57cec5SDimitry Andric         displayed_something = true;
501*0b57cec5SDimitry Andric     }
502*0b57cec5SDimitry Andric     if (!displayed_something) {
503*0b57cec5SDimitry Andric       result.AppendErrorWithFormat("No source filenames matched '%s'.\n",
504*0b57cec5SDimitry Andric                                    filename);
505*0b57cec5SDimitry Andric       return false;
506*0b57cec5SDimitry Andric     }
507*0b57cec5SDimitry Andric     return true;
508*0b57cec5SDimitry Andric   }
509*0b57cec5SDimitry Andric 
510*0b57cec5SDimitry Andric   // Dump the line entries for the current frame.
511*0b57cec5SDimitry Andric   bool DumpLinesForFrame(CommandReturnObject &result) {
512*0b57cec5SDimitry Andric     StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
513*0b57cec5SDimitry Andric     if (cur_frame == nullptr) {
514*0b57cec5SDimitry Andric       result.AppendError(
515*0b57cec5SDimitry Andric           "No selected frame to use to find the default source.");
516*0b57cec5SDimitry Andric       return false;
517*0b57cec5SDimitry Andric     } else if (!cur_frame->HasDebugInformation()) {
518*0b57cec5SDimitry Andric       result.AppendError("No debug info for the selected frame.");
519*0b57cec5SDimitry Andric       return false;
520*0b57cec5SDimitry Andric     } else {
521*0b57cec5SDimitry Andric       const SymbolContext &sc =
522*0b57cec5SDimitry Andric           cur_frame->GetSymbolContext(eSymbolContextLineEntry);
523*0b57cec5SDimitry Andric       SymbolContextList sc_list;
524*0b57cec5SDimitry Andric       sc_list.Append(sc);
525*0b57cec5SDimitry Andric       ModuleList module_list;
526*0b57cec5SDimitry Andric       FileSpec file_spec;
527*0b57cec5SDimitry Andric       if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list,
528*0b57cec5SDimitry Andric                                      module_list, file_spec)) {
529*0b57cec5SDimitry Andric         result.AppendError(
530*0b57cec5SDimitry Andric             "No source line info available for the selected frame.");
531*0b57cec5SDimitry Andric         return false;
532*0b57cec5SDimitry Andric       }
533*0b57cec5SDimitry Andric     }
534*0b57cec5SDimitry Andric     return true;
535*0b57cec5SDimitry Andric   }
536*0b57cec5SDimitry Andric 
537*0b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
538*0b57cec5SDimitry Andric     const size_t argc = command.GetArgumentCount();
539*0b57cec5SDimitry Andric 
540*0b57cec5SDimitry Andric     if (argc != 0) {
541*0b57cec5SDimitry Andric       result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n",
542*0b57cec5SDimitry Andric                                    GetCommandName().str().c_str());
543*0b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
544*0b57cec5SDimitry Andric       return false;
545*0b57cec5SDimitry Andric     }
546*0b57cec5SDimitry Andric 
547*0b57cec5SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
548*0b57cec5SDimitry Andric     if (target == nullptr) {
549*0b57cec5SDimitry Andric       target = GetDebugger().GetSelectedTarget().get();
550*0b57cec5SDimitry Andric       if (target == nullptr) {
551*0b57cec5SDimitry Andric         result.AppendError("invalid target, create a debug target using the "
552*0b57cec5SDimitry Andric                            "'target create' command.");
553*0b57cec5SDimitry Andric         result.SetStatus(eReturnStatusFailed);
554*0b57cec5SDimitry Andric         return false;
555*0b57cec5SDimitry Andric       }
556*0b57cec5SDimitry Andric     }
557*0b57cec5SDimitry Andric 
558*0b57cec5SDimitry Andric     uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
559*0b57cec5SDimitry Andric     result.GetOutputStream().SetAddressByteSize(addr_byte_size);
560*0b57cec5SDimitry Andric     result.GetErrorStream().SetAddressByteSize(addr_byte_size);
561*0b57cec5SDimitry Andric 
562*0b57cec5SDimitry Andric     // Collect the list of modules to search.
563*0b57cec5SDimitry Andric     m_module_list.Clear();
564*0b57cec5SDimitry Andric     if (!m_options.modules.empty()) {
565*0b57cec5SDimitry Andric       for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) {
566*0b57cec5SDimitry Andric         FileSpec module_file_spec(m_options.modules[i]);
567*0b57cec5SDimitry Andric         if (module_file_spec) {
568*0b57cec5SDimitry Andric           ModuleSpec module_spec(module_file_spec);
5699dba64beSDimitry Andric           target->GetImages().FindModules(module_spec, m_module_list);
5709dba64beSDimitry Andric           if (m_module_list.IsEmpty())
571*0b57cec5SDimitry Andric             result.AppendWarningWithFormat("No module found for '%s'.\n",
572*0b57cec5SDimitry Andric                                            m_options.modules[i].c_str());
573*0b57cec5SDimitry Andric         }
574*0b57cec5SDimitry Andric       }
575*0b57cec5SDimitry Andric       if (!m_module_list.GetSize()) {
576*0b57cec5SDimitry Andric         result.AppendError("No modules match the input.");
577*0b57cec5SDimitry Andric         result.SetStatus(eReturnStatusFailed);
578*0b57cec5SDimitry Andric         return false;
579*0b57cec5SDimitry Andric       }
580*0b57cec5SDimitry Andric     } else if (target->GetImages().GetSize() == 0) {
581*0b57cec5SDimitry Andric       result.AppendError("The target has no associated executable images.");
582*0b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
583*0b57cec5SDimitry Andric       return false;
584*0b57cec5SDimitry Andric     }
585*0b57cec5SDimitry Andric 
586*0b57cec5SDimitry Andric     // Check the arguments to see what lines we should dump.
587*0b57cec5SDimitry Andric     if (!m_options.symbol_name.empty()) {
588*0b57cec5SDimitry Andric       // Print lines for symbol.
589*0b57cec5SDimitry Andric       if (DumpLinesInFunctions(result))
590*0b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishResult);
591*0b57cec5SDimitry Andric       else
592*0b57cec5SDimitry Andric         result.SetStatus(eReturnStatusFailed);
593*0b57cec5SDimitry Andric     } else if (m_options.address != LLDB_INVALID_ADDRESS) {
594*0b57cec5SDimitry Andric       // Print lines for an address.
595*0b57cec5SDimitry Andric       if (DumpLinesForAddress(result))
596*0b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishResult);
597*0b57cec5SDimitry Andric       else
598*0b57cec5SDimitry Andric         result.SetStatus(eReturnStatusFailed);
599*0b57cec5SDimitry Andric     } else if (!m_options.file_name.empty()) {
600*0b57cec5SDimitry Andric       // Dump lines for a file.
601*0b57cec5SDimitry Andric       if (DumpLinesForFile(result))
602*0b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishResult);
603*0b57cec5SDimitry Andric       else
604*0b57cec5SDimitry Andric         result.SetStatus(eReturnStatusFailed);
605*0b57cec5SDimitry Andric     } else {
606*0b57cec5SDimitry Andric       // Dump the line for the current frame.
607*0b57cec5SDimitry Andric       if (DumpLinesForFrame(result))
608*0b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishResult);
609*0b57cec5SDimitry Andric       else
610*0b57cec5SDimitry Andric         result.SetStatus(eReturnStatusFailed);
611*0b57cec5SDimitry Andric     }
612*0b57cec5SDimitry Andric     return result.Succeeded();
613*0b57cec5SDimitry Andric   }
614*0b57cec5SDimitry Andric 
615*0b57cec5SDimitry Andric   CommandOptions m_options;
616*0b57cec5SDimitry Andric   ModuleList m_module_list;
617*0b57cec5SDimitry Andric };
618*0b57cec5SDimitry Andric 
619*0b57cec5SDimitry Andric #pragma mark CommandObjectSourceList
620*0b57cec5SDimitry Andric // CommandObjectSourceList
6219dba64beSDimitry Andric #define LLDB_OPTIONS_source_list
6229dba64beSDimitry Andric #include "CommandOptions.inc"
623*0b57cec5SDimitry Andric 
624*0b57cec5SDimitry Andric class CommandObjectSourceList : public CommandObjectParsed {
625*0b57cec5SDimitry Andric   class CommandOptions : public Options {
626*0b57cec5SDimitry Andric   public:
627*0b57cec5SDimitry Andric     CommandOptions() : Options() {}
628*0b57cec5SDimitry Andric 
629*0b57cec5SDimitry Andric     ~CommandOptions() override = default;
630*0b57cec5SDimitry Andric 
631*0b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
632*0b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
633*0b57cec5SDimitry Andric       Status error;
634*0b57cec5SDimitry Andric       const int short_option = GetDefinitions()[option_idx].short_option;
635*0b57cec5SDimitry Andric       switch (short_option) {
636*0b57cec5SDimitry Andric       case 'l':
637*0b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, start_line))
638*0b57cec5SDimitry Andric           error.SetErrorStringWithFormat("invalid line number: '%s'",
639*0b57cec5SDimitry Andric                                          option_arg.str().c_str());
640*0b57cec5SDimitry Andric         break;
641*0b57cec5SDimitry Andric 
642*0b57cec5SDimitry Andric       case 'c':
643*0b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, num_lines))
644*0b57cec5SDimitry Andric           error.SetErrorStringWithFormat("invalid line count: '%s'",
645*0b57cec5SDimitry Andric                                          option_arg.str().c_str());
646*0b57cec5SDimitry Andric         break;
647*0b57cec5SDimitry Andric 
648*0b57cec5SDimitry Andric       case 'f':
6495ffd83dbSDimitry Andric         file_name = std::string(option_arg);
650*0b57cec5SDimitry Andric         break;
651*0b57cec5SDimitry Andric 
652*0b57cec5SDimitry Andric       case 'n':
6535ffd83dbSDimitry Andric         symbol_name = std::string(option_arg);
654*0b57cec5SDimitry Andric         break;
655*0b57cec5SDimitry Andric 
656*0b57cec5SDimitry Andric       case 'a': {
657*0b57cec5SDimitry Andric         address = OptionArgParser::ToAddress(execution_context, option_arg,
658*0b57cec5SDimitry Andric                                              LLDB_INVALID_ADDRESS, &error);
659*0b57cec5SDimitry Andric       } break;
660*0b57cec5SDimitry Andric       case 's':
661*0b57cec5SDimitry Andric         modules.push_back(std::string(option_arg));
662*0b57cec5SDimitry Andric         break;
663*0b57cec5SDimitry Andric 
664*0b57cec5SDimitry Andric       case 'b':
665*0b57cec5SDimitry Andric         show_bp_locs = true;
666*0b57cec5SDimitry Andric         break;
667*0b57cec5SDimitry Andric       case 'r':
668*0b57cec5SDimitry Andric         reverse = true;
669*0b57cec5SDimitry Andric         break;
670*0b57cec5SDimitry Andric       default:
6719dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
672*0b57cec5SDimitry Andric       }
673*0b57cec5SDimitry Andric 
674*0b57cec5SDimitry Andric       return error;
675*0b57cec5SDimitry Andric     }
676*0b57cec5SDimitry Andric 
677*0b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
678*0b57cec5SDimitry Andric       file_spec.Clear();
679*0b57cec5SDimitry Andric       file_name.clear();
680*0b57cec5SDimitry Andric       symbol_name.clear();
681*0b57cec5SDimitry Andric       address = LLDB_INVALID_ADDRESS;
682*0b57cec5SDimitry Andric       start_line = 0;
683*0b57cec5SDimitry Andric       num_lines = 0;
684*0b57cec5SDimitry Andric       show_bp_locs = false;
685*0b57cec5SDimitry Andric       reverse = false;
686*0b57cec5SDimitry Andric       modules.clear();
687*0b57cec5SDimitry Andric     }
688*0b57cec5SDimitry Andric 
689*0b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
690*0b57cec5SDimitry Andric       return llvm::makeArrayRef(g_source_list_options);
691*0b57cec5SDimitry Andric     }
692*0b57cec5SDimitry Andric 
693*0b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
694*0b57cec5SDimitry Andric     FileSpec file_spec;
695*0b57cec5SDimitry Andric     std::string file_name;
696*0b57cec5SDimitry Andric     std::string symbol_name;
697*0b57cec5SDimitry Andric     lldb::addr_t address;
698*0b57cec5SDimitry Andric     uint32_t start_line;
699*0b57cec5SDimitry Andric     uint32_t num_lines;
700480093f4SDimitry Andric     std::vector<std::string> modules;
701*0b57cec5SDimitry Andric     bool show_bp_locs;
702*0b57cec5SDimitry Andric     bool reverse;
703*0b57cec5SDimitry Andric   };
704*0b57cec5SDimitry Andric 
705*0b57cec5SDimitry Andric public:
706*0b57cec5SDimitry Andric   CommandObjectSourceList(CommandInterpreter &interpreter)
707*0b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "source list",
708*0b57cec5SDimitry Andric                             "Display source code for the current target "
709*0b57cec5SDimitry Andric                             "process as specified by options.",
710*0b57cec5SDimitry Andric                             nullptr, eCommandRequiresTarget),
711*0b57cec5SDimitry Andric         m_options() {}
712*0b57cec5SDimitry Andric 
713*0b57cec5SDimitry Andric   ~CommandObjectSourceList() override = default;
714*0b57cec5SDimitry Andric 
715*0b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
716*0b57cec5SDimitry Andric 
717*0b57cec5SDimitry Andric   const char *GetRepeatCommand(Args &current_command_args,
718*0b57cec5SDimitry Andric                                uint32_t index) override {
719*0b57cec5SDimitry Andric     // This is kind of gross, but the command hasn't been parsed yet so we
720*0b57cec5SDimitry Andric     // can't look at the option values for this invocation...  I have to scan
721*0b57cec5SDimitry Andric     // the arguments directly.
722*0b57cec5SDimitry Andric     auto iter =
723*0b57cec5SDimitry Andric         llvm::find_if(current_command_args, [](const Args::ArgEntry &e) {
7249dba64beSDimitry Andric           return e.ref() == "-r" || e.ref() == "--reverse";
725*0b57cec5SDimitry Andric         });
726*0b57cec5SDimitry Andric     if (iter == current_command_args.end())
727*0b57cec5SDimitry Andric       return m_cmd_name.c_str();
728*0b57cec5SDimitry Andric 
729*0b57cec5SDimitry Andric     if (m_reverse_name.empty()) {
730*0b57cec5SDimitry Andric       m_reverse_name = m_cmd_name;
731*0b57cec5SDimitry Andric       m_reverse_name.append(" -r");
732*0b57cec5SDimitry Andric     }
733*0b57cec5SDimitry Andric     return m_reverse_name.c_str();
734*0b57cec5SDimitry Andric   }
735*0b57cec5SDimitry Andric 
736*0b57cec5SDimitry Andric protected:
737*0b57cec5SDimitry Andric   struct SourceInfo {
738*0b57cec5SDimitry Andric     ConstString function;
739*0b57cec5SDimitry Andric     LineEntry line_entry;
740*0b57cec5SDimitry Andric 
741*0b57cec5SDimitry Andric     SourceInfo(ConstString name, const LineEntry &line_entry)
742*0b57cec5SDimitry Andric         : function(name), line_entry(line_entry) {}
743*0b57cec5SDimitry Andric 
744*0b57cec5SDimitry Andric     SourceInfo() : function(), line_entry() {}
745*0b57cec5SDimitry Andric 
746*0b57cec5SDimitry Andric     bool IsValid() const { return (bool)function && line_entry.IsValid(); }
747*0b57cec5SDimitry Andric 
748*0b57cec5SDimitry Andric     bool operator==(const SourceInfo &rhs) const {
749*0b57cec5SDimitry Andric       return function == rhs.function &&
750*0b57cec5SDimitry Andric              line_entry.original_file == rhs.line_entry.original_file &&
751*0b57cec5SDimitry Andric              line_entry.line == rhs.line_entry.line;
752*0b57cec5SDimitry Andric     }
753*0b57cec5SDimitry Andric 
754*0b57cec5SDimitry Andric     bool operator!=(const SourceInfo &rhs) const {
755*0b57cec5SDimitry Andric       return function != rhs.function ||
756*0b57cec5SDimitry Andric              line_entry.original_file != rhs.line_entry.original_file ||
757*0b57cec5SDimitry Andric              line_entry.line != rhs.line_entry.line;
758*0b57cec5SDimitry Andric     }
759*0b57cec5SDimitry Andric 
760*0b57cec5SDimitry Andric     bool operator<(const SourceInfo &rhs) const {
761*0b57cec5SDimitry Andric       if (function.GetCString() < rhs.function.GetCString())
762*0b57cec5SDimitry Andric         return true;
763*0b57cec5SDimitry Andric       if (line_entry.file.GetDirectory().GetCString() <
764*0b57cec5SDimitry Andric           rhs.line_entry.file.GetDirectory().GetCString())
765*0b57cec5SDimitry Andric         return true;
766*0b57cec5SDimitry Andric       if (line_entry.file.GetFilename().GetCString() <
767*0b57cec5SDimitry Andric           rhs.line_entry.file.GetFilename().GetCString())
768*0b57cec5SDimitry Andric         return true;
769*0b57cec5SDimitry Andric       if (line_entry.line < rhs.line_entry.line)
770*0b57cec5SDimitry Andric         return true;
771*0b57cec5SDimitry Andric       return false;
772*0b57cec5SDimitry Andric     }
773*0b57cec5SDimitry Andric   };
774*0b57cec5SDimitry Andric 
775*0b57cec5SDimitry Andric   size_t DisplayFunctionSource(const SymbolContext &sc, SourceInfo &source_info,
776*0b57cec5SDimitry Andric                                CommandReturnObject &result) {
777*0b57cec5SDimitry Andric     if (!source_info.IsValid()) {
778*0b57cec5SDimitry Andric       source_info.function = sc.GetFunctionName();
779*0b57cec5SDimitry Andric       source_info.line_entry = sc.GetFunctionStartLineEntry();
780*0b57cec5SDimitry Andric     }
781*0b57cec5SDimitry Andric 
782*0b57cec5SDimitry Andric     if (sc.function) {
783*0b57cec5SDimitry Andric       Target *target = m_exe_ctx.GetTargetPtr();
784*0b57cec5SDimitry Andric 
785*0b57cec5SDimitry Andric       FileSpec start_file;
786*0b57cec5SDimitry Andric       uint32_t start_line;
787*0b57cec5SDimitry Andric       uint32_t end_line;
788*0b57cec5SDimitry Andric       FileSpec end_file;
789*0b57cec5SDimitry Andric 
790*0b57cec5SDimitry Andric       if (sc.block == nullptr) {
791*0b57cec5SDimitry Andric         // Not an inlined function
792*0b57cec5SDimitry Andric         sc.function->GetStartLineSourceInfo(start_file, start_line);
793*0b57cec5SDimitry Andric         if (start_line == 0) {
794*0b57cec5SDimitry Andric           result.AppendErrorWithFormat("Could not find line information for "
795*0b57cec5SDimitry Andric                                        "start of function: \"%s\".\n",
796*0b57cec5SDimitry Andric                                        source_info.function.GetCString());
797*0b57cec5SDimitry Andric           result.SetStatus(eReturnStatusFailed);
798*0b57cec5SDimitry Andric           return 0;
799*0b57cec5SDimitry Andric         }
800*0b57cec5SDimitry Andric         sc.function->GetEndLineSourceInfo(end_file, end_line);
801*0b57cec5SDimitry Andric       } else {
802*0b57cec5SDimitry Andric         // We have an inlined function
803*0b57cec5SDimitry Andric         start_file = source_info.line_entry.file;
804*0b57cec5SDimitry Andric         start_line = source_info.line_entry.line;
805*0b57cec5SDimitry Andric         end_line = start_line + m_options.num_lines;
806*0b57cec5SDimitry Andric       }
807*0b57cec5SDimitry Andric 
808*0b57cec5SDimitry Andric       // This is a little hacky, but the first line table entry for a function
809*0b57cec5SDimitry Andric       // points to the "{" that starts the function block.  It would be nice to
810*0b57cec5SDimitry Andric       // actually get the function declaration in there too.  So back up a bit,
811*0b57cec5SDimitry Andric       // but not further than what you're going to display.
812*0b57cec5SDimitry Andric       uint32_t extra_lines;
813*0b57cec5SDimitry Andric       if (m_options.num_lines >= 10)
814*0b57cec5SDimitry Andric         extra_lines = 5;
815*0b57cec5SDimitry Andric       else
816*0b57cec5SDimitry Andric         extra_lines = m_options.num_lines / 2;
817*0b57cec5SDimitry Andric       uint32_t line_no;
818*0b57cec5SDimitry Andric       if (start_line <= extra_lines)
819*0b57cec5SDimitry Andric         line_no = 1;
820*0b57cec5SDimitry Andric       else
821*0b57cec5SDimitry Andric         line_no = start_line - extra_lines;
822*0b57cec5SDimitry Andric 
823*0b57cec5SDimitry Andric       // For fun, if the function is shorter than the number of lines we're
824*0b57cec5SDimitry Andric       // supposed to display, only display the function...
825*0b57cec5SDimitry Andric       if (end_line != 0) {
826*0b57cec5SDimitry Andric         if (m_options.num_lines > end_line - line_no)
827*0b57cec5SDimitry Andric           m_options.num_lines = end_line - line_no + extra_lines;
828*0b57cec5SDimitry Andric       }
829*0b57cec5SDimitry Andric 
830*0b57cec5SDimitry Andric       m_breakpoint_locations.Clear();
831*0b57cec5SDimitry Andric 
832*0b57cec5SDimitry Andric       if (m_options.show_bp_locs) {
833*0b57cec5SDimitry Andric         const bool show_inlines = true;
834*0b57cec5SDimitry Andric         m_breakpoint_locations.Reset(start_file, 0, show_inlines);
835*0b57cec5SDimitry Andric         SearchFilterForUnconstrainedSearches target_search_filter(
836*0b57cec5SDimitry Andric             m_exe_ctx.GetTargetSP());
837*0b57cec5SDimitry Andric         target_search_filter.Search(m_breakpoint_locations);
838*0b57cec5SDimitry Andric       }
839*0b57cec5SDimitry Andric 
840*0b57cec5SDimitry Andric       result.AppendMessageWithFormat("File: %s\n",
841*0b57cec5SDimitry Andric                                      start_file.GetPath().c_str());
842*0b57cec5SDimitry Andric       // We don't care about the column here.
843*0b57cec5SDimitry Andric       const uint32_t column = 0;
844*0b57cec5SDimitry Andric       return target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
845*0b57cec5SDimitry Andric           start_file, line_no, column, 0, m_options.num_lines, "",
846*0b57cec5SDimitry Andric           &result.GetOutputStream(), GetBreakpointLocations());
847*0b57cec5SDimitry Andric     } else {
848*0b57cec5SDimitry Andric       result.AppendErrorWithFormat(
849*0b57cec5SDimitry Andric           "Could not find function info for: \"%s\".\n",
850*0b57cec5SDimitry Andric           m_options.symbol_name.c_str());
851*0b57cec5SDimitry Andric     }
852*0b57cec5SDimitry Andric     return 0;
853*0b57cec5SDimitry Andric   }
854*0b57cec5SDimitry Andric 
855*0b57cec5SDimitry Andric   // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols
856*0b57cec5SDimitry Andric   // functions "take a possibly empty vector of strings which are names of
857*0b57cec5SDimitry Andric   // modules, and run the two search functions on the subset of the full module
858*0b57cec5SDimitry Andric   // list that matches the strings in the input vector". If we wanted to put
859*0b57cec5SDimitry Andric   // these somewhere, there should probably be a module-filter-list that can be
860*0b57cec5SDimitry Andric   // passed to the various ModuleList::Find* calls, which would either be a
861*0b57cec5SDimitry Andric   // vector of string names or a ModuleSpecList.
8629dba64beSDimitry Andric   void FindMatchingFunctions(Target *target, ConstString name,
863*0b57cec5SDimitry Andric                              SymbolContextList &sc_list) {
864*0b57cec5SDimitry Andric     // Displaying the source for a symbol:
865*0b57cec5SDimitry Andric     bool include_inlines = true;
866*0b57cec5SDimitry Andric     bool include_symbols = false;
867*0b57cec5SDimitry Andric 
868*0b57cec5SDimitry Andric     if (m_options.num_lines == 0)
869*0b57cec5SDimitry Andric       m_options.num_lines = 10;
870*0b57cec5SDimitry Andric 
871*0b57cec5SDimitry Andric     const size_t num_modules = m_options.modules.size();
872*0b57cec5SDimitry Andric     if (num_modules > 0) {
873*0b57cec5SDimitry Andric       ModuleList matching_modules;
874*0b57cec5SDimitry Andric       for (size_t i = 0; i < num_modules; ++i) {
875*0b57cec5SDimitry Andric         FileSpec module_file_spec(m_options.modules[i]);
876*0b57cec5SDimitry Andric         if (module_file_spec) {
877*0b57cec5SDimitry Andric           ModuleSpec module_spec(module_file_spec);
878*0b57cec5SDimitry Andric           matching_modules.Clear();
879*0b57cec5SDimitry Andric           target->GetImages().FindModules(module_spec, matching_modules);
880480093f4SDimitry Andric           matching_modules.FindFunctions(name, eFunctionNameTypeAuto,
881480093f4SDimitry Andric                                          include_symbols, include_inlines,
8829dba64beSDimitry Andric                                          sc_list);
883*0b57cec5SDimitry Andric         }
884*0b57cec5SDimitry Andric       }
885*0b57cec5SDimitry Andric     } else {
8869dba64beSDimitry Andric       target->GetImages().FindFunctions(name, eFunctionNameTypeAuto,
8879dba64beSDimitry Andric                                         include_symbols, include_inlines,
888*0b57cec5SDimitry Andric                                         sc_list);
889*0b57cec5SDimitry Andric     }
890*0b57cec5SDimitry Andric   }
891*0b57cec5SDimitry Andric 
8929dba64beSDimitry Andric   void FindMatchingFunctionSymbols(Target *target, ConstString name,
893*0b57cec5SDimitry Andric                                    SymbolContextList &sc_list) {
894*0b57cec5SDimitry Andric     const size_t num_modules = m_options.modules.size();
895*0b57cec5SDimitry Andric     if (num_modules > 0) {
896*0b57cec5SDimitry Andric       ModuleList matching_modules;
897*0b57cec5SDimitry Andric       for (size_t i = 0; i < num_modules; ++i) {
898*0b57cec5SDimitry Andric         FileSpec module_file_spec(m_options.modules[i]);
899*0b57cec5SDimitry Andric         if (module_file_spec) {
900*0b57cec5SDimitry Andric           ModuleSpec module_spec(module_file_spec);
901*0b57cec5SDimitry Andric           matching_modules.Clear();
902*0b57cec5SDimitry Andric           target->GetImages().FindModules(module_spec, matching_modules);
9039dba64beSDimitry Andric           matching_modules.FindFunctionSymbols(name, eFunctionNameTypeAuto,
9049dba64beSDimitry Andric                                                sc_list);
905*0b57cec5SDimitry Andric         }
906*0b57cec5SDimitry Andric       }
907*0b57cec5SDimitry Andric     } else {
9089dba64beSDimitry Andric       target->GetImages().FindFunctionSymbols(name, eFunctionNameTypeAuto,
9099dba64beSDimitry Andric                                               sc_list);
910*0b57cec5SDimitry Andric     }
911*0b57cec5SDimitry Andric   }
912*0b57cec5SDimitry Andric 
913*0b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
914*0b57cec5SDimitry Andric     const size_t argc = command.GetArgumentCount();
915*0b57cec5SDimitry Andric 
916*0b57cec5SDimitry Andric     if (argc != 0) {
917*0b57cec5SDimitry Andric       result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n",
918*0b57cec5SDimitry Andric                                    GetCommandName().str().c_str());
919*0b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
920*0b57cec5SDimitry Andric       return false;
921*0b57cec5SDimitry Andric     }
922*0b57cec5SDimitry Andric 
923*0b57cec5SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
924*0b57cec5SDimitry Andric 
925*0b57cec5SDimitry Andric     if (!m_options.symbol_name.empty()) {
926*0b57cec5SDimitry Andric       SymbolContextList sc_list;
927*0b57cec5SDimitry Andric       ConstString name(m_options.symbol_name.c_str());
928*0b57cec5SDimitry Andric 
929*0b57cec5SDimitry Andric       // Displaying the source for a symbol. Search for function named name.
9309dba64beSDimitry Andric       FindMatchingFunctions(target, name, sc_list);
9319dba64beSDimitry Andric       size_t num_matches = sc_list.GetSize();
932*0b57cec5SDimitry Andric       if (!num_matches) {
933*0b57cec5SDimitry Andric         // If we didn't find any functions with that name, try searching for
934*0b57cec5SDimitry Andric         // symbols that line up exactly with function addresses.
935*0b57cec5SDimitry Andric         SymbolContextList sc_list_symbols;
936*0b57cec5SDimitry Andric         FindMatchingFunctionSymbols(target, name, sc_list_symbols);
9379dba64beSDimitry Andric         size_t num_symbol_matches = sc_list_symbols.GetSize();
9389dba64beSDimitry Andric 
939*0b57cec5SDimitry Andric         for (size_t i = 0; i < num_symbol_matches; i++) {
940*0b57cec5SDimitry Andric           SymbolContext sc;
941*0b57cec5SDimitry Andric           sc_list_symbols.GetContextAtIndex(i, sc);
942*0b57cec5SDimitry Andric           if (sc.symbol && sc.symbol->ValueIsAddress()) {
943*0b57cec5SDimitry Andric             const Address &base_address = sc.symbol->GetAddressRef();
944*0b57cec5SDimitry Andric             Function *function = base_address.CalculateSymbolContextFunction();
945*0b57cec5SDimitry Andric             if (function) {
946*0b57cec5SDimitry Andric               sc_list.Append(SymbolContext(function));
947*0b57cec5SDimitry Andric               num_matches++;
948*0b57cec5SDimitry Andric               break;
949*0b57cec5SDimitry Andric             }
950*0b57cec5SDimitry Andric           }
951*0b57cec5SDimitry Andric         }
952*0b57cec5SDimitry Andric       }
953*0b57cec5SDimitry Andric 
954*0b57cec5SDimitry Andric       if (num_matches == 0) {
955*0b57cec5SDimitry Andric         result.AppendErrorWithFormat("Could not find function named: \"%s\".\n",
956*0b57cec5SDimitry Andric                                      m_options.symbol_name.c_str());
957*0b57cec5SDimitry Andric         result.SetStatus(eReturnStatusFailed);
958*0b57cec5SDimitry Andric         return false;
959*0b57cec5SDimitry Andric       }
960*0b57cec5SDimitry Andric 
961*0b57cec5SDimitry Andric       if (num_matches > 1) {
962*0b57cec5SDimitry Andric         std::set<SourceInfo> source_match_set;
963*0b57cec5SDimitry Andric 
964*0b57cec5SDimitry Andric         bool displayed_something = false;
965*0b57cec5SDimitry Andric         for (size_t i = 0; i < num_matches; i++) {
966*0b57cec5SDimitry Andric           SymbolContext sc;
967*0b57cec5SDimitry Andric           sc_list.GetContextAtIndex(i, sc);
968*0b57cec5SDimitry Andric           SourceInfo source_info(sc.GetFunctionName(),
969*0b57cec5SDimitry Andric                                  sc.GetFunctionStartLineEntry());
970*0b57cec5SDimitry Andric 
971*0b57cec5SDimitry Andric           if (source_info.IsValid()) {
972*0b57cec5SDimitry Andric             if (source_match_set.find(source_info) == source_match_set.end()) {
973*0b57cec5SDimitry Andric               source_match_set.insert(source_info);
974*0b57cec5SDimitry Andric               if (DisplayFunctionSource(sc, source_info, result))
975*0b57cec5SDimitry Andric                 displayed_something = true;
976*0b57cec5SDimitry Andric             }
977*0b57cec5SDimitry Andric           }
978*0b57cec5SDimitry Andric         }
979*0b57cec5SDimitry Andric 
980*0b57cec5SDimitry Andric         if (displayed_something)
981*0b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishResult);
982*0b57cec5SDimitry Andric         else
983*0b57cec5SDimitry Andric           result.SetStatus(eReturnStatusFailed);
984*0b57cec5SDimitry Andric       } else {
985*0b57cec5SDimitry Andric         SymbolContext sc;
986*0b57cec5SDimitry Andric         sc_list.GetContextAtIndex(0, sc);
987*0b57cec5SDimitry Andric         SourceInfo source_info;
988*0b57cec5SDimitry Andric 
989*0b57cec5SDimitry Andric         if (DisplayFunctionSource(sc, source_info, result)) {
990*0b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishResult);
991*0b57cec5SDimitry Andric         } else {
992*0b57cec5SDimitry Andric           result.SetStatus(eReturnStatusFailed);
993*0b57cec5SDimitry Andric         }
994*0b57cec5SDimitry Andric       }
995*0b57cec5SDimitry Andric       return result.Succeeded();
996*0b57cec5SDimitry Andric     } else if (m_options.address != LLDB_INVALID_ADDRESS) {
997*0b57cec5SDimitry Andric       Address so_addr;
998*0b57cec5SDimitry Andric       StreamString error_strm;
999*0b57cec5SDimitry Andric       SymbolContextList sc_list;
1000*0b57cec5SDimitry Andric 
1001*0b57cec5SDimitry Andric       if (target->GetSectionLoadList().IsEmpty()) {
1002*0b57cec5SDimitry Andric         // The target isn't loaded yet, we need to lookup the file address in
1003*0b57cec5SDimitry Andric         // all modules
1004*0b57cec5SDimitry Andric         const ModuleList &module_list = target->GetImages();
1005*0b57cec5SDimitry Andric         const size_t num_modules = module_list.GetSize();
1006*0b57cec5SDimitry Andric         for (size_t i = 0; i < num_modules; ++i) {
1007*0b57cec5SDimitry Andric           ModuleSP module_sp(module_list.GetModuleAtIndex(i));
1008*0b57cec5SDimitry Andric           if (module_sp &&
1009*0b57cec5SDimitry Andric               module_sp->ResolveFileAddress(m_options.address, so_addr)) {
1010*0b57cec5SDimitry Andric             SymbolContext sc;
1011*0b57cec5SDimitry Andric             sc.Clear(true);
1012*0b57cec5SDimitry Andric             if (module_sp->ResolveSymbolContextForAddress(
1013*0b57cec5SDimitry Andric                     so_addr, eSymbolContextEverything, sc) &
1014*0b57cec5SDimitry Andric                 eSymbolContextLineEntry)
1015*0b57cec5SDimitry Andric               sc_list.Append(sc);
1016*0b57cec5SDimitry Andric           }
1017*0b57cec5SDimitry Andric         }
1018*0b57cec5SDimitry Andric 
1019*0b57cec5SDimitry Andric         if (sc_list.GetSize() == 0) {
1020*0b57cec5SDimitry Andric           result.AppendErrorWithFormat(
1021*0b57cec5SDimitry Andric               "no modules have source information for file address 0x%" PRIx64
1022*0b57cec5SDimitry Andric               ".\n",
1023*0b57cec5SDimitry Andric               m_options.address);
1024*0b57cec5SDimitry Andric           result.SetStatus(eReturnStatusFailed);
1025*0b57cec5SDimitry Andric           return false;
1026*0b57cec5SDimitry Andric         }
1027*0b57cec5SDimitry Andric       } else {
1028*0b57cec5SDimitry Andric         // The target has some things loaded, resolve this address to a compile
1029*0b57cec5SDimitry Andric         // unit + file + line and display
1030*0b57cec5SDimitry Andric         if (target->GetSectionLoadList().ResolveLoadAddress(m_options.address,
1031*0b57cec5SDimitry Andric                                                             so_addr)) {
1032*0b57cec5SDimitry Andric           ModuleSP module_sp(so_addr.GetModule());
1033*0b57cec5SDimitry Andric           if (module_sp) {
1034*0b57cec5SDimitry Andric             SymbolContext sc;
1035*0b57cec5SDimitry Andric             sc.Clear(true);
1036*0b57cec5SDimitry Andric             if (module_sp->ResolveSymbolContextForAddress(
1037*0b57cec5SDimitry Andric                     so_addr, eSymbolContextEverything, sc) &
1038*0b57cec5SDimitry Andric                 eSymbolContextLineEntry) {
1039*0b57cec5SDimitry Andric               sc_list.Append(sc);
1040*0b57cec5SDimitry Andric             } else {
1041*0b57cec5SDimitry Andric               so_addr.Dump(&error_strm, nullptr,
1042*0b57cec5SDimitry Andric                            Address::DumpStyleModuleWithFileAddress);
1043*0b57cec5SDimitry Andric               result.AppendErrorWithFormat("address resolves to %s, but there "
1044*0b57cec5SDimitry Andric                                            "is no line table information "
1045*0b57cec5SDimitry Andric                                            "available for this address.\n",
1046*0b57cec5SDimitry Andric                                            error_strm.GetData());
1047*0b57cec5SDimitry Andric               result.SetStatus(eReturnStatusFailed);
1048*0b57cec5SDimitry Andric               return false;
1049*0b57cec5SDimitry Andric             }
1050*0b57cec5SDimitry Andric           }
1051*0b57cec5SDimitry Andric         }
1052*0b57cec5SDimitry Andric 
1053*0b57cec5SDimitry Andric         if (sc_list.GetSize() == 0) {
1054*0b57cec5SDimitry Andric           result.AppendErrorWithFormat(
1055*0b57cec5SDimitry Andric               "no modules contain load address 0x%" PRIx64 ".\n",
1056*0b57cec5SDimitry Andric               m_options.address);
1057*0b57cec5SDimitry Andric           result.SetStatus(eReturnStatusFailed);
1058*0b57cec5SDimitry Andric           return false;
1059*0b57cec5SDimitry Andric         }
1060*0b57cec5SDimitry Andric       }
1061*0b57cec5SDimitry Andric       uint32_t num_matches = sc_list.GetSize();
1062*0b57cec5SDimitry Andric       for (uint32_t i = 0; i < num_matches; ++i) {
1063*0b57cec5SDimitry Andric         SymbolContext sc;
1064*0b57cec5SDimitry Andric         sc_list.GetContextAtIndex(i, sc);
1065*0b57cec5SDimitry Andric         if (sc.comp_unit) {
1066*0b57cec5SDimitry Andric           if (m_options.show_bp_locs) {
1067*0b57cec5SDimitry Andric             m_breakpoint_locations.Clear();
1068*0b57cec5SDimitry Andric             const bool show_inlines = true;
1069480093f4SDimitry Andric             m_breakpoint_locations.Reset(sc.comp_unit->GetPrimaryFile(), 0,
1070480093f4SDimitry Andric                                          show_inlines);
1071*0b57cec5SDimitry Andric             SearchFilterForUnconstrainedSearches target_search_filter(
1072*0b57cec5SDimitry Andric                 target->shared_from_this());
1073*0b57cec5SDimitry Andric             target_search_filter.Search(m_breakpoint_locations);
1074*0b57cec5SDimitry Andric           }
1075*0b57cec5SDimitry Andric 
1076*0b57cec5SDimitry Andric           bool show_fullpaths = true;
1077*0b57cec5SDimitry Andric           bool show_module = true;
1078*0b57cec5SDimitry Andric           bool show_inlined_frames = true;
1079*0b57cec5SDimitry Andric           const bool show_function_arguments = true;
1080*0b57cec5SDimitry Andric           const bool show_function_name = true;
1081*0b57cec5SDimitry Andric           sc.DumpStopContext(&result.GetOutputStream(),
1082*0b57cec5SDimitry Andric                              m_exe_ctx.GetBestExecutionContextScope(),
1083*0b57cec5SDimitry Andric                              sc.line_entry.range.GetBaseAddress(),
1084*0b57cec5SDimitry Andric                              show_fullpaths, show_module, show_inlined_frames,
1085*0b57cec5SDimitry Andric                              show_function_arguments, show_function_name);
1086*0b57cec5SDimitry Andric           result.GetOutputStream().EOL();
1087*0b57cec5SDimitry Andric 
1088*0b57cec5SDimitry Andric           if (m_options.num_lines == 0)
1089*0b57cec5SDimitry Andric             m_options.num_lines = 10;
1090*0b57cec5SDimitry Andric 
1091*0b57cec5SDimitry Andric           size_t lines_to_back_up =
1092*0b57cec5SDimitry Andric               m_options.num_lines >= 10 ? 5 : m_options.num_lines / 2;
1093*0b57cec5SDimitry Andric 
1094*0b57cec5SDimitry Andric           const uint32_t column =
1095*0b57cec5SDimitry Andric               (GetDebugger().GetStopShowColumn() != eStopShowColumnNone)
1096*0b57cec5SDimitry Andric                   ? sc.line_entry.column
1097*0b57cec5SDimitry Andric                   : 0;
1098*0b57cec5SDimitry Andric           target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
1099480093f4SDimitry Andric               sc.comp_unit->GetPrimaryFile(), sc.line_entry.line, column,
1100480093f4SDimitry Andric               lines_to_back_up, m_options.num_lines - lines_to_back_up, "->",
1101*0b57cec5SDimitry Andric               &result.GetOutputStream(), GetBreakpointLocations());
1102*0b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishResult);
1103*0b57cec5SDimitry Andric         }
1104*0b57cec5SDimitry Andric       }
1105*0b57cec5SDimitry Andric     } else if (m_options.file_name.empty()) {
1106*0b57cec5SDimitry Andric       // Last valid source manager context, or the current frame if no valid
1107*0b57cec5SDimitry Andric       // last context in source manager. One little trick here, if you type the
1108*0b57cec5SDimitry Andric       // exact same list command twice in a row, it is more likely because you
1109*0b57cec5SDimitry Andric       // typed it once, then typed it again
1110*0b57cec5SDimitry Andric       if (m_options.start_line == 0) {
1111*0b57cec5SDimitry Andric         if (target->GetSourceManager().DisplayMoreWithLineNumbers(
1112*0b57cec5SDimitry Andric                 &result.GetOutputStream(), m_options.num_lines,
1113*0b57cec5SDimitry Andric                 m_options.reverse, GetBreakpointLocations())) {
1114*0b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishResult);
1115*0b57cec5SDimitry Andric         }
1116*0b57cec5SDimitry Andric       } else {
1117*0b57cec5SDimitry Andric         if (m_options.num_lines == 0)
1118*0b57cec5SDimitry Andric           m_options.num_lines = 10;
1119*0b57cec5SDimitry Andric 
1120*0b57cec5SDimitry Andric         if (m_options.show_bp_locs) {
1121*0b57cec5SDimitry Andric           SourceManager::FileSP last_file_sp(
1122*0b57cec5SDimitry Andric               target->GetSourceManager().GetLastFile());
1123*0b57cec5SDimitry Andric           if (last_file_sp) {
1124*0b57cec5SDimitry Andric             const bool show_inlines = true;
1125*0b57cec5SDimitry Andric             m_breakpoint_locations.Reset(last_file_sp->GetFileSpec(), 0,
1126*0b57cec5SDimitry Andric                                          show_inlines);
1127*0b57cec5SDimitry Andric             SearchFilterForUnconstrainedSearches target_search_filter(
1128*0b57cec5SDimitry Andric                 target->shared_from_this());
1129*0b57cec5SDimitry Andric             target_search_filter.Search(m_breakpoint_locations);
1130*0b57cec5SDimitry Andric           }
1131*0b57cec5SDimitry Andric         } else
1132*0b57cec5SDimitry Andric           m_breakpoint_locations.Clear();
1133*0b57cec5SDimitry Andric 
1134*0b57cec5SDimitry Andric         const uint32_t column = 0;
1135*0b57cec5SDimitry Andric         if (target->GetSourceManager()
1136*0b57cec5SDimitry Andric                 .DisplaySourceLinesWithLineNumbersUsingLastFile(
1137*0b57cec5SDimitry Andric                     m_options.start_line, // Line to display
1138*0b57cec5SDimitry Andric                     m_options.num_lines,  // Lines after line to
1139*0b57cec5SDimitry Andric                     UINT32_MAX,           // Don't mark "line"
1140*0b57cec5SDimitry Andric                     column,
1141*0b57cec5SDimitry Andric                     "", // Don't mark "line"
1142*0b57cec5SDimitry Andric                     &result.GetOutputStream(), GetBreakpointLocations())) {
1143*0b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishResult);
1144*0b57cec5SDimitry Andric         }
1145*0b57cec5SDimitry Andric       }
1146*0b57cec5SDimitry Andric     } else {
1147*0b57cec5SDimitry Andric       const char *filename = m_options.file_name.c_str();
1148*0b57cec5SDimitry Andric 
1149*0b57cec5SDimitry Andric       bool check_inlines = false;
1150*0b57cec5SDimitry Andric       SymbolContextList sc_list;
1151*0b57cec5SDimitry Andric       size_t num_matches = 0;
1152*0b57cec5SDimitry Andric 
1153*0b57cec5SDimitry Andric       if (!m_options.modules.empty()) {
1154*0b57cec5SDimitry Andric         ModuleList matching_modules;
1155*0b57cec5SDimitry Andric         for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) {
1156*0b57cec5SDimitry Andric           FileSpec module_file_spec(m_options.modules[i]);
1157*0b57cec5SDimitry Andric           if (module_file_spec) {
1158*0b57cec5SDimitry Andric             ModuleSpec module_spec(module_file_spec);
1159*0b57cec5SDimitry Andric             matching_modules.Clear();
1160*0b57cec5SDimitry Andric             target->GetImages().FindModules(module_spec, matching_modules);
1161*0b57cec5SDimitry Andric             num_matches += matching_modules.ResolveSymbolContextForFilePath(
1162*0b57cec5SDimitry Andric                 filename, 0, check_inlines,
1163*0b57cec5SDimitry Andric                 SymbolContextItem(eSymbolContextModule |
1164*0b57cec5SDimitry Andric                                   eSymbolContextCompUnit),
1165*0b57cec5SDimitry Andric                 sc_list);
1166*0b57cec5SDimitry Andric           }
1167*0b57cec5SDimitry Andric         }
1168*0b57cec5SDimitry Andric       } else {
1169*0b57cec5SDimitry Andric         num_matches = target->GetImages().ResolveSymbolContextForFilePath(
1170*0b57cec5SDimitry Andric             filename, 0, check_inlines,
1171*0b57cec5SDimitry Andric             eSymbolContextModule | eSymbolContextCompUnit, sc_list);
1172*0b57cec5SDimitry Andric       }
1173*0b57cec5SDimitry Andric 
1174*0b57cec5SDimitry Andric       if (num_matches == 0) {
1175*0b57cec5SDimitry Andric         result.AppendErrorWithFormat("Could not find source file \"%s\".\n",
1176*0b57cec5SDimitry Andric                                      m_options.file_name.c_str());
1177*0b57cec5SDimitry Andric         result.SetStatus(eReturnStatusFailed);
1178*0b57cec5SDimitry Andric         return false;
1179*0b57cec5SDimitry Andric       }
1180*0b57cec5SDimitry Andric 
1181*0b57cec5SDimitry Andric       if (num_matches > 1) {
1182*0b57cec5SDimitry Andric         bool got_multiple = false;
1183480093f4SDimitry Andric         CompileUnit *test_cu = nullptr;
1184*0b57cec5SDimitry Andric 
1185*0b57cec5SDimitry Andric         for (unsigned i = 0; i < num_matches; i++) {
1186*0b57cec5SDimitry Andric           SymbolContext sc;
1187*0b57cec5SDimitry Andric           sc_list.GetContextAtIndex(i, sc);
1188*0b57cec5SDimitry Andric           if (sc.comp_unit) {
1189480093f4SDimitry Andric             if (test_cu) {
1190480093f4SDimitry Andric               if (test_cu != sc.comp_unit)
1191*0b57cec5SDimitry Andric                 got_multiple = true;
1192*0b57cec5SDimitry Andric               break;
1193*0b57cec5SDimitry Andric             } else
1194480093f4SDimitry Andric               test_cu = sc.comp_unit;
1195*0b57cec5SDimitry Andric           }
1196*0b57cec5SDimitry Andric         }
1197*0b57cec5SDimitry Andric         if (got_multiple) {
1198*0b57cec5SDimitry Andric           result.AppendErrorWithFormat(
1199*0b57cec5SDimitry Andric               "Multiple source files found matching: \"%s.\"\n",
1200*0b57cec5SDimitry Andric               m_options.file_name.c_str());
1201*0b57cec5SDimitry Andric           result.SetStatus(eReturnStatusFailed);
1202*0b57cec5SDimitry Andric           return false;
1203*0b57cec5SDimitry Andric         }
1204*0b57cec5SDimitry Andric       }
1205*0b57cec5SDimitry Andric 
1206*0b57cec5SDimitry Andric       SymbolContext sc;
1207*0b57cec5SDimitry Andric       if (sc_list.GetContextAtIndex(0, sc)) {
1208*0b57cec5SDimitry Andric         if (sc.comp_unit) {
1209*0b57cec5SDimitry Andric           if (m_options.show_bp_locs) {
1210*0b57cec5SDimitry Andric             const bool show_inlines = true;
1211480093f4SDimitry Andric             m_breakpoint_locations.Reset(sc.comp_unit->GetPrimaryFile(), 0,
1212480093f4SDimitry Andric                                          show_inlines);
1213*0b57cec5SDimitry Andric             SearchFilterForUnconstrainedSearches target_search_filter(
1214*0b57cec5SDimitry Andric                 target->shared_from_this());
1215*0b57cec5SDimitry Andric             target_search_filter.Search(m_breakpoint_locations);
1216*0b57cec5SDimitry Andric           } else
1217*0b57cec5SDimitry Andric             m_breakpoint_locations.Clear();
1218*0b57cec5SDimitry Andric 
1219*0b57cec5SDimitry Andric           if (m_options.num_lines == 0)
1220*0b57cec5SDimitry Andric             m_options.num_lines = 10;
1221*0b57cec5SDimitry Andric           const uint32_t column = 0;
1222*0b57cec5SDimitry Andric           target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
1223480093f4SDimitry Andric               sc.comp_unit->GetPrimaryFile(), m_options.start_line, column, 0,
1224480093f4SDimitry Andric               m_options.num_lines, "", &result.GetOutputStream(),
1225480093f4SDimitry Andric               GetBreakpointLocations());
1226*0b57cec5SDimitry Andric 
1227*0b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishResult);
1228*0b57cec5SDimitry Andric         } else {
1229*0b57cec5SDimitry Andric           result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n",
1230*0b57cec5SDimitry Andric                                        m_options.file_name.c_str());
1231*0b57cec5SDimitry Andric           result.SetStatus(eReturnStatusFailed);
1232*0b57cec5SDimitry Andric           return false;
1233*0b57cec5SDimitry Andric         }
1234*0b57cec5SDimitry Andric       }
1235*0b57cec5SDimitry Andric     }
1236*0b57cec5SDimitry Andric     return result.Succeeded();
1237*0b57cec5SDimitry Andric   }
1238*0b57cec5SDimitry Andric 
1239*0b57cec5SDimitry Andric   const SymbolContextList *GetBreakpointLocations() {
1240*0b57cec5SDimitry Andric     if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0)
1241*0b57cec5SDimitry Andric       return &m_breakpoint_locations.GetFileLineMatches();
1242*0b57cec5SDimitry Andric     return nullptr;
1243*0b57cec5SDimitry Andric   }
1244*0b57cec5SDimitry Andric 
1245*0b57cec5SDimitry Andric   CommandOptions m_options;
1246*0b57cec5SDimitry Andric   FileLineResolver m_breakpoint_locations;
1247*0b57cec5SDimitry Andric   std::string m_reverse_name;
1248*0b57cec5SDimitry Andric };
1249*0b57cec5SDimitry Andric 
1250*0b57cec5SDimitry Andric #pragma mark CommandObjectMultiwordSource
1251*0b57cec5SDimitry Andric // CommandObjectMultiwordSource
1252*0b57cec5SDimitry Andric 
1253*0b57cec5SDimitry Andric CommandObjectMultiwordSource::CommandObjectMultiwordSource(
1254*0b57cec5SDimitry Andric     CommandInterpreter &interpreter)
1255480093f4SDimitry Andric     : CommandObjectMultiword(interpreter, "source",
1256480093f4SDimitry Andric                              "Commands for examining "
1257*0b57cec5SDimitry Andric                              "source code described by "
1258*0b57cec5SDimitry Andric                              "debug information for the "
1259*0b57cec5SDimitry Andric                              "current target process.",
1260*0b57cec5SDimitry Andric                              "source <subcommand> [<subcommand-options>]") {
1261*0b57cec5SDimitry Andric   LoadSubCommand("info",
1262*0b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectSourceInfo(interpreter)));
1263*0b57cec5SDimitry Andric   LoadSubCommand("list",
1264*0b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectSourceList(interpreter)));
1265*0b57cec5SDimitry Andric }
1266*0b57cec5SDimitry Andric 
1267*0b57cec5SDimitry Andric CommandObjectMultiwordSource::~CommandObjectMultiwordSource() = default;
1268