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