xref: /src/contrib/llvm-project/lldb/source/Commands/CommandObjectSource.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1cfca06d7SDimitry Andric //===-- CommandObjectSource.cpp -------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste 
9f034231aSEd Maste #include "CommandObjectSource.h"
10f034231aSEd Maste 
11f034231aSEd Maste #include "lldb/Core/Debugger.h"
12f034231aSEd Maste #include "lldb/Core/FileLineResolver.h"
13f034231aSEd Maste #include "lldb/Core/Module.h"
14f034231aSEd Maste #include "lldb/Core/ModuleSpec.h"
15f034231aSEd Maste #include "lldb/Core/SourceManager.h"
1674a628f7SDimitry Andric #include "lldb/Host/OptionParser.h"
174b4fe385SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h"
1814f1b3e8SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
19f73363f1SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
20b60736ecSDimitry Andric #include "lldb/Interpreter/OptionValueFileColonLine.h"
2114f1b3e8SDimitry Andric #include "lldb/Interpreter/Options.h"
22f034231aSEd Maste #include "lldb/Symbol/CompileUnit.h"
23f034231aSEd Maste #include "lldb/Symbol/Function.h"
24f034231aSEd Maste #include "lldb/Symbol/Symbol.h"
257fa27ce4SDimitry Andric #include "lldb/Target/Process.h"
26866dcdacSEd Maste #include "lldb/Target/SectionLoadList.h"
279e6d3549SDimitry Andric #include "lldb/Target/StackFrame.h"
2874a628f7SDimitry Andric #include "lldb/Utility/FileSpec.h"
29e3b55780SDimitry Andric #include <optional>
30f034231aSEd Maste 
31f034231aSEd Maste using namespace lldb;
32f034231aSEd Maste using namespace lldb_private;
33f034231aSEd Maste 
349e6d3549SDimitry Andric #pragma mark CommandObjectSourceInfo
359e6d3549SDimitry Andric // CommandObjectSourceInfo - debug line entries dumping command
36ead24645SDimitry Andric #define LLDB_OPTIONS_source_info
37ead24645SDimitry Andric #include "CommandOptions.inc"
3814f1b3e8SDimitry Andric 
3914f1b3e8SDimitry Andric class CommandObjectSourceInfo : public CommandObjectParsed {
4014f1b3e8SDimitry Andric   class CommandOptions : public Options {
41f034231aSEd Maste   public:
42145449b1SDimitry Andric     CommandOptions() = default;
43f034231aSEd Maste 
44f3fbd1c0SDimitry Andric     ~CommandOptions() override = default;
45f034231aSEd Maste 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)46b76161e4SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
4714f1b3e8SDimitry Andric                           ExecutionContext *execution_context) override {
48b76161e4SDimitry Andric       Status error;
4914f1b3e8SDimitry Andric       const int short_option = GetDefinitions()[option_idx].short_option;
5014f1b3e8SDimitry Andric       switch (short_option) {
51f034231aSEd Maste       case 'l':
5214f1b3e8SDimitry Andric         if (option_arg.getAsInteger(0, start_line))
5314f1b3e8SDimitry Andric           error.SetErrorStringWithFormat("invalid line number: '%s'",
5414f1b3e8SDimitry Andric                                          option_arg.str().c_str());
55f034231aSEd Maste         break;
56f034231aSEd Maste 
579e6d3549SDimitry Andric       case 'e':
5814f1b3e8SDimitry Andric         if (option_arg.getAsInteger(0, end_line))
5914f1b3e8SDimitry Andric           error.SetErrorStringWithFormat("invalid line number: '%s'",
6014f1b3e8SDimitry Andric                                          option_arg.str().c_str());
619e6d3549SDimitry Andric         break;
629e6d3549SDimitry Andric 
639e6d3549SDimitry Andric       case 'c':
6414f1b3e8SDimitry Andric         if (option_arg.getAsInteger(0, num_lines))
6514f1b3e8SDimitry Andric           error.SetErrorStringWithFormat("invalid line count: '%s'",
6614f1b3e8SDimitry Andric                                          option_arg.str().c_str());
679e6d3549SDimitry Andric         break;
689e6d3549SDimitry Andric 
69f034231aSEd Maste       case 'f':
70cfca06d7SDimitry Andric         file_name = std::string(option_arg);
71f034231aSEd Maste         break;
72f034231aSEd Maste 
739e6d3549SDimitry Andric       case 'n':
74cfca06d7SDimitry Andric         symbol_name = std::string(option_arg);
759e6d3549SDimitry Andric         break;
769e6d3549SDimitry Andric 
7714f1b3e8SDimitry Andric       case 'a': {
78f73363f1SDimitry Andric         address = OptionArgParser::ToAddress(execution_context, option_arg,
7914f1b3e8SDimitry Andric                                              LLDB_INVALID_ADDRESS, &error);
8014f1b3e8SDimitry Andric       } break;
819e6d3549SDimitry Andric       case 's':
829e6d3549SDimitry Andric         modules.push_back(std::string(option_arg));
839e6d3549SDimitry Andric         break;
84f034231aSEd Maste       default:
85ead24645SDimitry Andric         llvm_unreachable("Unimplemented option");
86f034231aSEd Maste       }
87f034231aSEd Maste 
88f034231aSEd Maste       return error;
89f034231aSEd Maste     }
90f034231aSEd Maste 
OptionParsingStarting(ExecutionContext * execution_context)9114f1b3e8SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
92f034231aSEd Maste       file_spec.Clear();
93f034231aSEd Maste       file_name.clear();
949e6d3549SDimitry Andric       symbol_name.clear();
959e6d3549SDimitry Andric       address = LLDB_INVALID_ADDRESS;
96f034231aSEd Maste       start_line = 0;
979e6d3549SDimitry Andric       end_line = 0;
989e6d3549SDimitry Andric       num_lines = 0;
999e6d3549SDimitry Andric       modules.clear();
100f034231aSEd Maste     }
101f034231aSEd Maste 
GetDefinitions()10214f1b3e8SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
103e3b55780SDimitry Andric       return llvm::ArrayRef(g_source_info_options);
104f034231aSEd Maste     }
105f3fbd1c0SDimitry Andric 
106f034231aSEd Maste     // Instance variables to hold the values for command options.
107f034231aSEd Maste     FileSpec file_spec;
108f034231aSEd Maste     std::string file_name;
1099e6d3549SDimitry Andric     std::string symbol_name;
1109e6d3549SDimitry Andric     lldb::addr_t address;
111f034231aSEd Maste     uint32_t start_line;
1129e6d3549SDimitry Andric     uint32_t end_line;
1139e6d3549SDimitry Andric     uint32_t num_lines;
114706b4fc4SDimitry Andric     std::vector<std::string> modules;
115f034231aSEd Maste   };
116f034231aSEd Maste 
117f034231aSEd Maste public:
CommandObjectSourceInfo(CommandInterpreter & interpreter)1189e6d3549SDimitry Andric   CommandObjectSourceInfo(CommandInterpreter &interpreter)
11914f1b3e8SDimitry Andric       : CommandObjectParsed(
12014f1b3e8SDimitry Andric             interpreter, "source info",
12114f1b3e8SDimitry Andric             "Display source line information for the current target "
122f3fbd1c0SDimitry Andric             "process.  Defaults to instruction pointer in current stack "
123f3fbd1c0SDimitry Andric             "frame.",
1246f8fc217SDimitry Andric             nullptr, eCommandRequiresTarget) {}
125f034231aSEd Maste 
126f3fbd1c0SDimitry Andric   ~CommandObjectSourceInfo() override = default;
127f034231aSEd Maste 
GetOptions()12814f1b3e8SDimitry Andric   Options *GetOptions() override { return &m_options; }
129f034231aSEd Maste 
130f034231aSEd Maste protected:
131f73363f1SDimitry Andric   // Dump the line entries in each symbol context. Return the number of entries
132f73363f1SDimitry Andric   // found. If module_list is set, only dump lines contained in one of the
133f73363f1SDimitry Andric   // modules. If file_spec is set, only dump lines in the file. If the
134f73363f1SDimitry Andric   // start_line option was specified, don't print lines less than start_line.
13514f1b3e8SDimitry Andric   // If the end_line option was specified, don't print lines greater than
136f73363f1SDimitry Andric   // end_line. If the num_lines option was specified, dont print more than
137f73363f1SDimitry Andric   // num_lines entries.
DumpLinesInSymbolContexts(Stream & strm,const SymbolContextList & sc_list,const ModuleList & module_list,const FileSpec & file_spec)13814f1b3e8SDimitry Andric   uint32_t DumpLinesInSymbolContexts(Stream &strm,
13914f1b3e8SDimitry Andric                                      const SymbolContextList &sc_list,
14014f1b3e8SDimitry Andric                                      const ModuleList &module_list,
14114f1b3e8SDimitry Andric                                      const FileSpec &file_spec) {
1429e6d3549SDimitry Andric     uint32_t start_line = m_options.start_line;
1439e6d3549SDimitry Andric     uint32_t end_line = m_options.end_line;
1449e6d3549SDimitry Andric     uint32_t num_lines = m_options.num_lines;
1459e6d3549SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
1469e6d3549SDimitry Andric 
1479e6d3549SDimitry Andric     uint32_t num_matches = 0;
1489e6d3549SDimitry Andric     // Dump all the line entries for the file in the list.
1499e6d3549SDimitry Andric     ConstString last_module_file_name;
1507fa27ce4SDimitry Andric     for (const SymbolContext &sc : sc_list) {
15114f1b3e8SDimitry Andric       if (sc.comp_unit) {
1529e6d3549SDimitry Andric         Module *module = sc.module_sp.get();
1539e6d3549SDimitry Andric         CompileUnit *cu = sc.comp_unit;
1549e6d3549SDimitry Andric         const LineEntry &line_entry = sc.line_entry;
1559e6d3549SDimitry Andric         assert(module && cu);
1569e6d3549SDimitry Andric 
1579e6d3549SDimitry Andric         // Are we looking for specific modules, files or lines?
15814f1b3e8SDimitry Andric         if (module_list.GetSize() &&
15914f1b3e8SDimitry Andric             module_list.GetIndexForModule(module) == LLDB_INVALID_INDEX32)
1609e6d3549SDimitry Andric           continue;
161ac9a064cSDimitry Andric         if (!FileSpec::Match(file_spec, line_entry.GetFile()))
1629e6d3549SDimitry Andric           continue;
1639e6d3549SDimitry Andric         if (start_line > 0 && line_entry.line < start_line)
1649e6d3549SDimitry Andric           continue;
1659e6d3549SDimitry Andric         if (end_line > 0 && line_entry.line > end_line)
1669e6d3549SDimitry Andric           continue;
1679e6d3549SDimitry Andric         if (num_lines > 0 && num_matches > num_lines)
1689e6d3549SDimitry Andric           continue;
1699e6d3549SDimitry Andric 
1709e6d3549SDimitry Andric         // Print a new header if the module changed.
171706b4fc4SDimitry Andric         ConstString module_file_name = module->GetFileSpec().GetFilename();
1729e6d3549SDimitry Andric         assert(module_file_name);
17314f1b3e8SDimitry Andric         if (module_file_name != last_module_file_name) {
1749e6d3549SDimitry Andric           if (num_matches > 0)
1759e6d3549SDimitry Andric             strm << "\n\n";
1769e6d3549SDimitry Andric           strm << "Lines found in module `" << module_file_name << "\n";
1779e6d3549SDimitry Andric         }
1789e6d3549SDimitry Andric         // Dump the line entry.
1799e6d3549SDimitry Andric         line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu,
1809e6d3549SDimitry Andric                                   target, /*show_address_only=*/false);
1819e6d3549SDimitry Andric         strm << "\n";
1829e6d3549SDimitry Andric         last_module_file_name = module_file_name;
1839e6d3549SDimitry Andric         num_matches++;
1849e6d3549SDimitry Andric       }
1859e6d3549SDimitry Andric     }
1869e6d3549SDimitry Andric     return num_matches;
1879e6d3549SDimitry Andric   }
1889e6d3549SDimitry Andric 
1899e6d3549SDimitry Andric   // Dump the requested line entries for the file in the compilation unit.
190f73363f1SDimitry Andric   // Return the number of entries found. If module_list is set, only dump lines
191f73363f1SDimitry Andric   // contained in one of the modules. If the start_line option was specified,
192f73363f1SDimitry Andric   // don't print lines less than start_line. If the end_line option was
193f73363f1SDimitry Andric   // specified, don't print lines greater than end_line. If the num_lines
194f73363f1SDimitry Andric   // option was specified, dont print more than num_lines entries.
DumpFileLinesInCompUnit(Stream & strm,Module * module,CompileUnit * cu,const FileSpec & file_spec)19514f1b3e8SDimitry Andric   uint32_t DumpFileLinesInCompUnit(Stream &strm, Module *module,
19614f1b3e8SDimitry Andric                                    CompileUnit *cu, const FileSpec &file_spec) {
1979e6d3549SDimitry Andric     uint32_t start_line = m_options.start_line;
1989e6d3549SDimitry Andric     uint32_t end_line = m_options.end_line;
1999e6d3549SDimitry Andric     uint32_t num_lines = m_options.num_lines;
2009e6d3549SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
2019e6d3549SDimitry Andric 
2029e6d3549SDimitry Andric     uint32_t num_matches = 0;
2039e6d3549SDimitry Andric     assert(module);
20414f1b3e8SDimitry Andric     if (cu) {
2059e6d3549SDimitry Andric       assert(file_spec.GetFilename().AsCString());
206f3fbd1c0SDimitry Andric       bool has_path = (file_spec.GetDirectory().AsCString() != nullptr);
207aca2e42cSDimitry Andric       const SupportFileList &cu_file_list = cu->GetSupportFiles();
2089e6d3549SDimitry Andric       size_t file_idx = cu_file_list.FindFileIndex(0, file_spec, has_path);
20914f1b3e8SDimitry Andric       if (file_idx != UINT32_MAX) {
2109e6d3549SDimitry Andric         // Update the file to how it appears in the CU.
21114f1b3e8SDimitry Andric         const FileSpec &cu_file_spec =
21214f1b3e8SDimitry Andric             cu_file_list.GetFileSpecAtIndex(file_idx);
2139e6d3549SDimitry Andric 
21414f1b3e8SDimitry Andric         // Dump all matching lines at or above start_line for the file in the
21514f1b3e8SDimitry Andric         // CU.
2165f29bb8aSDimitry Andric         ConstString file_spec_name = file_spec.GetFilename();
217706b4fc4SDimitry Andric         ConstString module_file_name = module->GetFileSpec().GetFilename();
2189e6d3549SDimitry Andric         bool cu_header_printed = false;
2199e6d3549SDimitry Andric         uint32_t line = start_line;
22014f1b3e8SDimitry Andric         while (true) {
2219e6d3549SDimitry Andric           LineEntry line_entry;
2229e6d3549SDimitry Andric 
223f73363f1SDimitry Andric           // Find the lowest index of a line entry with a line equal to or
224f73363f1SDimitry Andric           // higher than 'line'.
2259e6d3549SDimitry Andric           uint32_t start_idx = 0;
2269e6d3549SDimitry Andric           start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec,
2279e6d3549SDimitry Andric                                         /*exact=*/false, &line_entry);
2289e6d3549SDimitry Andric           if (start_idx == UINT32_MAX)
2299e6d3549SDimitry Andric             // No more line entries for our file in this CU.
2309e6d3549SDimitry Andric             break;
2319e6d3549SDimitry Andric 
2329e6d3549SDimitry Andric           if (end_line > 0 && line_entry.line > end_line)
2339e6d3549SDimitry Andric             break;
2349e6d3549SDimitry Andric 
235f73363f1SDimitry Andric           // Loop through to find any other entries for this line, dumping
236f73363f1SDimitry Andric           // each.
2379e6d3549SDimitry Andric           line = line_entry.line;
23814f1b3e8SDimitry Andric           do {
2399e6d3549SDimitry Andric             num_matches++;
2409e6d3549SDimitry Andric             if (num_lines > 0 && num_matches > num_lines)
2419e6d3549SDimitry Andric               break;
242ac9a064cSDimitry Andric             assert(cu_file_spec == line_entry.GetFile());
24314f1b3e8SDimitry Andric             if (!cu_header_printed) {
2449e6d3549SDimitry Andric               if (num_matches > 0)
2459e6d3549SDimitry Andric                 strm << "\n\n";
2469e6d3549SDimitry Andric               strm << "Lines found for file " << file_spec_name
247706b4fc4SDimitry Andric                    << " in compilation unit "
248706b4fc4SDimitry Andric                    << cu->GetPrimaryFile().GetFilename() << " in `"
24914f1b3e8SDimitry Andric                    << module_file_name << "\n";
2509e6d3549SDimitry Andric               cu_header_printed = true;
2519e6d3549SDimitry Andric             }
2529e6d3549SDimitry Andric             line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu,
2539e6d3549SDimitry Andric                                       target, /*show_address_only=*/false);
2549e6d3549SDimitry Andric             strm << "\n";
2559e6d3549SDimitry Andric 
2569e6d3549SDimitry Andric             // Anymore after this one?
2579e6d3549SDimitry Andric             start_idx++;
2589e6d3549SDimitry Andric             start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec,
2599e6d3549SDimitry Andric                                           /*exact=*/true, &line_entry);
2609e6d3549SDimitry Andric           } while (start_idx != UINT32_MAX);
2619e6d3549SDimitry Andric 
2629e6d3549SDimitry Andric           // Try the next higher line, starting over at start_idx 0.
2639e6d3549SDimitry Andric           line++;
2649e6d3549SDimitry Andric         }
2659e6d3549SDimitry Andric       }
2669e6d3549SDimitry Andric     }
2679e6d3549SDimitry Andric     return num_matches;
2689e6d3549SDimitry Andric   }
2699e6d3549SDimitry Andric 
270f73363f1SDimitry Andric   // Dump the requested line entries for the file in the module. Return the
271f73363f1SDimitry Andric   // number of entries found. If module_list is set, only dump lines contained
272f73363f1SDimitry Andric   // in one of the modules. If the start_line option was specified, don't print
273f73363f1SDimitry Andric   // lines less than start_line. If the end_line option was specified, don't
274f73363f1SDimitry Andric   // print lines greater than end_line. If the num_lines option was specified,
275f73363f1SDimitry Andric   // dont print more than num_lines entries.
DumpFileLinesInModule(Stream & strm,Module * module,const FileSpec & file_spec)27614f1b3e8SDimitry Andric   uint32_t DumpFileLinesInModule(Stream &strm, Module *module,
27714f1b3e8SDimitry Andric                                  const FileSpec &file_spec) {
2789e6d3549SDimitry Andric     uint32_t num_matches = 0;
27914f1b3e8SDimitry Andric     if (module) {
28014f1b3e8SDimitry Andric       // Look through all the compilation units (CUs) in this module for ones
281f73363f1SDimitry Andric       // that contain lines of code from this source file.
28214f1b3e8SDimitry Andric       for (size_t i = 0; i < module->GetNumCompileUnits(); i++) {
2839e6d3549SDimitry Andric         // Look for a matching source file in this CU.
2849e6d3549SDimitry Andric         CompUnitSP cu_sp(module->GetCompileUnitAtIndex(i));
28514f1b3e8SDimitry Andric         if (cu_sp) {
28614f1b3e8SDimitry Andric           num_matches +=
28714f1b3e8SDimitry Andric               DumpFileLinesInCompUnit(strm, module, cu_sp.get(), file_spec);
2889e6d3549SDimitry Andric         }
2899e6d3549SDimitry Andric       }
2909e6d3549SDimitry Andric     }
2919e6d3549SDimitry Andric     return num_matches;
2929e6d3549SDimitry Andric   }
2939e6d3549SDimitry Andric 
29414f1b3e8SDimitry Andric   // Given an address and a list of modules, append the symbol contexts of all
295f73363f1SDimitry Andric   // line entries containing the address found in the modules and return the
296f73363f1SDimitry Andric   // count of matches.  If none is found, return an error in 'error_strm'.
GetSymbolContextsForAddress(const ModuleList & module_list,lldb::addr_t addr,SymbolContextList & sc_list,StreamString & error_strm)29714f1b3e8SDimitry Andric   size_t GetSymbolContextsForAddress(const ModuleList &module_list,
29814f1b3e8SDimitry Andric                                      lldb::addr_t addr,
29914f1b3e8SDimitry Andric                                      SymbolContextList &sc_list,
30014f1b3e8SDimitry Andric                                      StreamString &error_strm) {
3019e6d3549SDimitry Andric     Address so_addr;
3029e6d3549SDimitry Andric     size_t num_matches = 0;
3039e6d3549SDimitry Andric     assert(module_list.GetSize() > 0);
3049e6d3549SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
30514f1b3e8SDimitry Andric     if (target->GetSectionLoadList().IsEmpty()) {
306f73363f1SDimitry Andric       // The target isn't loaded yet, we need to lookup the file address in all
307f73363f1SDimitry Andric       // modules.  Note: the module list option does not apply to addresses.
3089e6d3549SDimitry Andric       const size_t num_modules = module_list.GetSize();
30914f1b3e8SDimitry Andric       for (size_t i = 0; i < num_modules; ++i) {
3109e6d3549SDimitry Andric         ModuleSP module_sp(module_list.GetModuleAtIndex(i));
3119e6d3549SDimitry Andric         if (!module_sp)
3129e6d3549SDimitry Andric           continue;
31314f1b3e8SDimitry Andric         if (module_sp->ResolveFileAddress(addr, so_addr)) {
3149e6d3549SDimitry Andric           SymbolContext sc;
3159e6d3549SDimitry Andric           sc.Clear(true);
31614f1b3e8SDimitry Andric           if (module_sp->ResolveSymbolContextForAddress(
31714f1b3e8SDimitry Andric                   so_addr, eSymbolContextEverything, sc) &
31814f1b3e8SDimitry Andric               eSymbolContextLineEntry) {
3199e6d3549SDimitry Andric             sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false);
3209e6d3549SDimitry Andric             ++num_matches;
3219e6d3549SDimitry Andric           }
3229e6d3549SDimitry Andric         }
3239e6d3549SDimitry Andric       }
3249e6d3549SDimitry Andric       if (num_matches == 0)
3259e6d3549SDimitry Andric         error_strm.Printf("Source information for file address 0x%" PRIx64
32614f1b3e8SDimitry Andric                           " not found in any modules.\n",
32714f1b3e8SDimitry Andric                           addr);
32814f1b3e8SDimitry Andric     } else {
329f73363f1SDimitry Andric       // The target has some things loaded, resolve this address to a compile
330f73363f1SDimitry Andric       // unit + file + line and display
33114f1b3e8SDimitry Andric       if (target->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) {
3329e6d3549SDimitry Andric         ModuleSP module_sp(so_addr.GetModule());
3339e6d3549SDimitry Andric         // Check to make sure this module is in our list.
334706b4fc4SDimitry Andric         if (module_sp && module_list.GetIndexForModule(module_sp.get()) !=
33514f1b3e8SDimitry Andric                              LLDB_INVALID_INDEX32) {
3369e6d3549SDimitry Andric           SymbolContext sc;
3379e6d3549SDimitry Andric           sc.Clear(true);
33814f1b3e8SDimitry Andric           if (module_sp->ResolveSymbolContextForAddress(
33914f1b3e8SDimitry Andric                   so_addr, eSymbolContextEverything, sc) &
34014f1b3e8SDimitry Andric               eSymbolContextLineEntry) {
3419e6d3549SDimitry Andric             sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false);
3429e6d3549SDimitry Andric             ++num_matches;
34314f1b3e8SDimitry Andric           } else {
3449e6d3549SDimitry Andric             StreamString addr_strm;
34514f1b3e8SDimitry Andric             so_addr.Dump(&addr_strm, nullptr,
34614f1b3e8SDimitry Andric                          Address::DumpStyleModuleWithFileAddress);
34714f1b3e8SDimitry Andric             error_strm.Printf(
34814f1b3e8SDimitry Andric                 "Address 0x%" PRIx64 " resolves to %s, but there is"
3499e6d3549SDimitry Andric                 " no source information available for this address.\n",
3509e6d3549SDimitry Andric                 addr, addr_strm.GetData());
3519e6d3549SDimitry Andric           }
35214f1b3e8SDimitry Andric         } else {
3539e6d3549SDimitry Andric           StreamString addr_strm;
35414f1b3e8SDimitry Andric           so_addr.Dump(&addr_strm, nullptr,
35514f1b3e8SDimitry Andric                        Address::DumpStyleModuleWithFileAddress);
35614f1b3e8SDimitry Andric           error_strm.Printf("Address 0x%" PRIx64
35714f1b3e8SDimitry Andric                             " resolves to %s, but it cannot"
3589e6d3549SDimitry Andric                             " be found in any modules.\n",
3599e6d3549SDimitry Andric                             addr, addr_strm.GetData());
3609e6d3549SDimitry Andric         }
36114f1b3e8SDimitry Andric       } else
3629e6d3549SDimitry Andric         error_strm.Printf("Unable to resolve address 0x%" PRIx64 ".\n", addr);
3639e6d3549SDimitry Andric     }
3649e6d3549SDimitry Andric     return num_matches;
3659e6d3549SDimitry Andric   }
3669e6d3549SDimitry Andric 
367f73363f1SDimitry Andric   // Dump the line entries found in functions matching the name specified in
368f73363f1SDimitry Andric   // the option.
DumpLinesInFunctions(CommandReturnObject & result)36914f1b3e8SDimitry Andric   bool DumpLinesInFunctions(CommandReturnObject &result) {
3709e6d3549SDimitry Andric     SymbolContextList sc_list_funcs;
3719e6d3549SDimitry Andric     ConstString name(m_options.symbol_name.c_str());
3729e6d3549SDimitry Andric     SymbolContextList sc_list_lines;
3739e6d3549SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
3749e6d3549SDimitry Andric     uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
3759e6d3549SDimitry Andric 
376c0981da4SDimitry Andric     ModuleFunctionSearchOptions function_options;
377c0981da4SDimitry Andric     function_options.include_symbols = false;
378c0981da4SDimitry Andric     function_options.include_inlines = true;
379c0981da4SDimitry Andric 
38014f1b3e8SDimitry Andric     // Note: module_list can't be const& because FindFunctionSymbols isn't
38114f1b3e8SDimitry Andric     // const.
38214f1b3e8SDimitry Andric     ModuleList module_list =
38314f1b3e8SDimitry Andric         (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages();
384c0981da4SDimitry Andric     module_list.FindFunctions(name, eFunctionNameTypeAuto, function_options,
385c0981da4SDimitry Andric                               sc_list_funcs);
386ead24645SDimitry Andric     size_t num_matches = sc_list_funcs.GetSize();
387ead24645SDimitry Andric 
38814f1b3e8SDimitry Andric     if (!num_matches) {
3899e6d3549SDimitry Andric       // If we didn't find any functions with that name, try searching for
3909e6d3549SDimitry Andric       // symbols that line up exactly with function addresses.
3919e6d3549SDimitry Andric       SymbolContextList sc_list_symbols;
392706b4fc4SDimitry Andric       module_list.FindFunctionSymbols(name, eFunctionNameTypeAuto,
393706b4fc4SDimitry Andric                                       sc_list_symbols);
3947fa27ce4SDimitry Andric       for (const SymbolContext &sc : sc_list_symbols) {
39514f1b3e8SDimitry Andric         if (sc.symbol && sc.symbol->ValueIsAddress()) {
3969e6d3549SDimitry Andric           const Address &base_address = sc.symbol->GetAddressRef();
3979e6d3549SDimitry Andric           Function *function = base_address.CalculateSymbolContextFunction();
39814f1b3e8SDimitry Andric           if (function) {
3999e6d3549SDimitry Andric             sc_list_funcs.Append(SymbolContext(function));
4009e6d3549SDimitry Andric             num_matches++;
4019e6d3549SDimitry Andric           }
4029e6d3549SDimitry Andric         }
4039e6d3549SDimitry Andric       }
4049e6d3549SDimitry Andric     }
40514f1b3e8SDimitry Andric     if (num_matches == 0) {
4069e6d3549SDimitry Andric       result.AppendErrorWithFormat("Could not find function named \'%s\'.\n",
4079e6d3549SDimitry Andric                                    m_options.symbol_name.c_str());
4089e6d3549SDimitry Andric       return false;
4099e6d3549SDimitry Andric     }
4107fa27ce4SDimitry Andric     for (const SymbolContext &sc : sc_list_funcs) {
4119e6d3549SDimitry Andric       bool context_found_for_symbol = false;
4129e6d3549SDimitry Andric       // Loop through all the ranges in the function.
4139e6d3549SDimitry Andric       AddressRange range;
4149e6d3549SDimitry Andric       for (uint32_t r = 0;
41514f1b3e8SDimitry Andric            sc.GetAddressRange(eSymbolContextEverything, r,
41614f1b3e8SDimitry Andric                               /*use_inline_block_range=*/true, range);
41714f1b3e8SDimitry Andric            ++r) {
41814f1b3e8SDimitry Andric         // Append the symbol contexts for each address in the range to
41914f1b3e8SDimitry Andric         // sc_list_lines.
4209e6d3549SDimitry Andric         const Address &base_address = range.GetBaseAddress();
4219e6d3549SDimitry Andric         const addr_t size = range.GetByteSize();
4229e6d3549SDimitry Andric         lldb::addr_t start_addr = base_address.GetLoadAddress(target);
4239e6d3549SDimitry Andric         if (start_addr == LLDB_INVALID_ADDRESS)
4249e6d3549SDimitry Andric           start_addr = base_address.GetFileAddress();
4259e6d3549SDimitry Andric         lldb::addr_t end_addr = start_addr + size;
42614f1b3e8SDimitry Andric         for (lldb::addr_t addr = start_addr; addr < end_addr;
42714f1b3e8SDimitry Andric              addr += addr_byte_size) {
4289e6d3549SDimitry Andric           StreamString error_strm;
42914f1b3e8SDimitry Andric           if (!GetSymbolContextsForAddress(module_list, addr, sc_list_lines,
43014f1b3e8SDimitry Andric                                            error_strm))
4319e6d3549SDimitry Andric             result.AppendWarningWithFormat("in symbol '%s': %s",
4329e6d3549SDimitry Andric                                            sc.GetFunctionName().AsCString(),
4339e6d3549SDimitry Andric                                            error_strm.GetData());
4349e6d3549SDimitry Andric           else
4359e6d3549SDimitry Andric             context_found_for_symbol = true;
4369e6d3549SDimitry Andric         }
4379e6d3549SDimitry Andric       }
4389e6d3549SDimitry Andric       if (!context_found_for_symbol)
4399e6d3549SDimitry Andric         result.AppendWarningWithFormat("Unable to find line information"
4409e6d3549SDimitry Andric                                        " for matching symbol '%s'.\n",
4419e6d3549SDimitry Andric                                        sc.GetFunctionName().AsCString());
4429e6d3549SDimitry Andric     }
44314f1b3e8SDimitry Andric     if (sc_list_lines.GetSize() == 0) {
4449e6d3549SDimitry Andric       result.AppendErrorWithFormat("No line information could be found"
4459e6d3549SDimitry Andric                                    " for any symbols matching '%s'.\n",
4469e6d3549SDimitry Andric                                    name.AsCString());
4479e6d3549SDimitry Andric       return false;
4489e6d3549SDimitry Andric     }
4499e6d3549SDimitry Andric     FileSpec file_spec;
45014f1b3e8SDimitry Andric     if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list_lines,
45114f1b3e8SDimitry Andric                                    module_list, file_spec)) {
45214f1b3e8SDimitry Andric       result.AppendErrorWithFormat(
45314f1b3e8SDimitry Andric           "Unable to dump line information for symbol '%s'.\n",
4549e6d3549SDimitry Andric           name.AsCString());
4559e6d3549SDimitry Andric       return false;
4569e6d3549SDimitry Andric     }
4579e6d3549SDimitry Andric     return true;
4589e6d3549SDimitry Andric   }
4599e6d3549SDimitry Andric 
4609e6d3549SDimitry Andric   // Dump the line entries found for the address specified in the option.
DumpLinesForAddress(CommandReturnObject & result)46114f1b3e8SDimitry Andric   bool DumpLinesForAddress(CommandReturnObject &result) {
4629e6d3549SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
4639e6d3549SDimitry Andric     SymbolContextList sc_list;
4649e6d3549SDimitry Andric 
4659e6d3549SDimitry Andric     StreamString error_strm;
46614f1b3e8SDimitry Andric     if (!GetSymbolContextsForAddress(target->GetImages(), m_options.address,
46714f1b3e8SDimitry Andric                                      sc_list, error_strm)) {
4689e6d3549SDimitry Andric       result.AppendErrorWithFormat("%s.\n", error_strm.GetData());
4699e6d3549SDimitry Andric       return false;
4709e6d3549SDimitry Andric     }
4719e6d3549SDimitry Andric     ModuleList module_list;
4729e6d3549SDimitry Andric     FileSpec file_spec;
47314f1b3e8SDimitry Andric     if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list,
47414f1b3e8SDimitry Andric                                    module_list, file_spec)) {
47514f1b3e8SDimitry Andric       result.AppendErrorWithFormat("No modules contain load address 0x%" PRIx64
47614f1b3e8SDimitry Andric                                    ".\n",
4779e6d3549SDimitry Andric                                    m_options.address);
4789e6d3549SDimitry Andric       return false;
4799e6d3549SDimitry Andric     }
4809e6d3549SDimitry Andric     return true;
4819e6d3549SDimitry Andric   }
4829e6d3549SDimitry Andric 
4839e6d3549SDimitry Andric   // Dump the line entries found in the file specified in the option.
DumpLinesForFile(CommandReturnObject & result)48414f1b3e8SDimitry Andric   bool DumpLinesForFile(CommandReturnObject &result) {
48594994d37SDimitry Andric     FileSpec file_spec(m_options.file_name);
4869e6d3549SDimitry Andric     const char *filename = m_options.file_name.c_str();
4879e6d3549SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
48814f1b3e8SDimitry Andric     const ModuleList &module_list =
48914f1b3e8SDimitry Andric         (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages();
4909e6d3549SDimitry Andric 
4919e6d3549SDimitry Andric     bool displayed_something = false;
4929e6d3549SDimitry Andric     const size_t num_modules = module_list.GetSize();
49314f1b3e8SDimitry Andric     for (uint32_t i = 0; i < num_modules; ++i) {
4949e6d3549SDimitry Andric       // Dump lines for this module.
4959e6d3549SDimitry Andric       Module *module = module_list.GetModulePointerAtIndex(i);
4969e6d3549SDimitry Andric       assert(module);
4979e6d3549SDimitry Andric       if (DumpFileLinesInModule(result.GetOutputStream(), module, file_spec))
4989e6d3549SDimitry Andric         displayed_something = true;
4999e6d3549SDimitry Andric     }
50014f1b3e8SDimitry Andric     if (!displayed_something) {
50114f1b3e8SDimitry Andric       result.AppendErrorWithFormat("No source filenames matched '%s'.\n",
50214f1b3e8SDimitry Andric                                    filename);
5039e6d3549SDimitry Andric       return false;
5049e6d3549SDimitry Andric     }
5059e6d3549SDimitry Andric     return true;
5069e6d3549SDimitry Andric   }
5079e6d3549SDimitry Andric 
5089e6d3549SDimitry Andric   // Dump the line entries for the current frame.
DumpLinesForFrame(CommandReturnObject & result)50914f1b3e8SDimitry Andric   bool DumpLinesForFrame(CommandReturnObject &result) {
5109e6d3549SDimitry Andric     StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
51114f1b3e8SDimitry Andric     if (cur_frame == nullptr) {
51214f1b3e8SDimitry Andric       result.AppendError(
51314f1b3e8SDimitry Andric           "No selected frame to use to find the default source.");
5149e6d3549SDimitry Andric       return false;
51514f1b3e8SDimitry Andric     } else if (!cur_frame->HasDebugInformation()) {
5169e6d3549SDimitry Andric       result.AppendError("No debug info for the selected frame.");
5179e6d3549SDimitry Andric       return false;
51814f1b3e8SDimitry Andric     } else {
51914f1b3e8SDimitry Andric       const SymbolContext &sc =
52014f1b3e8SDimitry Andric           cur_frame->GetSymbolContext(eSymbolContextLineEntry);
5219e6d3549SDimitry Andric       SymbolContextList sc_list;
5229e6d3549SDimitry Andric       sc_list.Append(sc);
5239e6d3549SDimitry Andric       ModuleList module_list;
5249e6d3549SDimitry Andric       FileSpec file_spec;
52514f1b3e8SDimitry Andric       if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list,
52614f1b3e8SDimitry Andric                                      module_list, file_spec)) {
52714f1b3e8SDimitry Andric         result.AppendError(
52814f1b3e8SDimitry Andric             "No source line info available for the selected frame.");
5299e6d3549SDimitry Andric         return false;
5309e6d3549SDimitry Andric       }
5319e6d3549SDimitry Andric     }
5329e6d3549SDimitry Andric     return true;
5339e6d3549SDimitry Andric   }
5349e6d3549SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)535b1c73532SDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
5369e6d3549SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
53714f1b3e8SDimitry Andric     if (target == nullptr) {
5385f29bb8aSDimitry Andric       target = GetDebugger().GetSelectedTarget().get();
53914f1b3e8SDimitry Andric       if (target == nullptr) {
5409e6d3549SDimitry Andric         result.AppendError("invalid target, create a debug target using the "
5419e6d3549SDimitry Andric                            "'target create' command.");
542b1c73532SDimitry Andric         return;
5439e6d3549SDimitry Andric       }
5449e6d3549SDimitry Andric     }
5459e6d3549SDimitry Andric 
5469e6d3549SDimitry Andric     uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
5479e6d3549SDimitry Andric     result.GetOutputStream().SetAddressByteSize(addr_byte_size);
5489e6d3549SDimitry Andric     result.GetErrorStream().SetAddressByteSize(addr_byte_size);
5499e6d3549SDimitry Andric 
5509e6d3549SDimitry Andric     // Collect the list of modules to search.
5519e6d3549SDimitry Andric     m_module_list.Clear();
55214f1b3e8SDimitry Andric     if (!m_options.modules.empty()) {
55314f1b3e8SDimitry Andric       for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) {
55494994d37SDimitry Andric         FileSpec module_file_spec(m_options.modules[i]);
55514f1b3e8SDimitry Andric         if (module_file_spec) {
5569e6d3549SDimitry Andric           ModuleSpec module_spec(module_file_spec);
557ead24645SDimitry Andric           target->GetImages().FindModules(module_spec, m_module_list);
558ead24645SDimitry Andric           if (m_module_list.IsEmpty())
5599e6d3549SDimitry Andric             result.AppendWarningWithFormat("No module found for '%s'.\n",
5609e6d3549SDimitry Andric                                            m_options.modules[i].c_str());
5619e6d3549SDimitry Andric         }
5629e6d3549SDimitry Andric       }
56314f1b3e8SDimitry Andric       if (!m_module_list.GetSize()) {
5649e6d3549SDimitry Andric         result.AppendError("No modules match the input.");
565b1c73532SDimitry Andric         return;
5669e6d3549SDimitry Andric       }
56714f1b3e8SDimitry Andric     } else if (target->GetImages().GetSize() == 0) {
5689e6d3549SDimitry Andric       result.AppendError("The target has no associated executable images.");
569b1c73532SDimitry Andric       return;
5709e6d3549SDimitry Andric     }
5719e6d3549SDimitry Andric 
5729e6d3549SDimitry Andric     // Check the arguments to see what lines we should dump.
57314f1b3e8SDimitry Andric     if (!m_options.symbol_name.empty()) {
5749e6d3549SDimitry Andric       // Print lines for symbol.
5759e6d3549SDimitry Andric       if (DumpLinesInFunctions(result))
5769e6d3549SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishResult);
5779e6d3549SDimitry Andric       else
5789e6d3549SDimitry Andric         result.SetStatus(eReturnStatusFailed);
57914f1b3e8SDimitry Andric     } else if (m_options.address != LLDB_INVALID_ADDRESS) {
5809e6d3549SDimitry Andric       // Print lines for an address.
5819e6d3549SDimitry Andric       if (DumpLinesForAddress(result))
5829e6d3549SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishResult);
5839e6d3549SDimitry Andric       else
5849e6d3549SDimitry Andric         result.SetStatus(eReturnStatusFailed);
58514f1b3e8SDimitry Andric     } else if (!m_options.file_name.empty()) {
5869e6d3549SDimitry Andric       // Dump lines for a file.
5879e6d3549SDimitry Andric       if (DumpLinesForFile(result))
5889e6d3549SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishResult);
5899e6d3549SDimitry Andric       else
5909e6d3549SDimitry Andric         result.SetStatus(eReturnStatusFailed);
59114f1b3e8SDimitry Andric     } else {
5929e6d3549SDimitry Andric       // Dump the line for the current frame.
5939e6d3549SDimitry Andric       if (DumpLinesForFrame(result))
5949e6d3549SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishResult);
5959e6d3549SDimitry Andric       else
5969e6d3549SDimitry Andric         result.SetStatus(eReturnStatusFailed);
5979e6d3549SDimitry Andric     }
5989e6d3549SDimitry Andric   }
5999e6d3549SDimitry Andric 
600f034231aSEd Maste   CommandOptions m_options;
6019e6d3549SDimitry Andric   ModuleList m_module_list;
602f034231aSEd Maste };
603f034231aSEd Maste 
604f034231aSEd Maste #pragma mark CommandObjectSourceList
605f034231aSEd Maste // CommandObjectSourceList
606ead24645SDimitry Andric #define LLDB_OPTIONS_source_list
607ead24645SDimitry Andric #include "CommandOptions.inc"
60814f1b3e8SDimitry Andric 
60914f1b3e8SDimitry Andric class CommandObjectSourceList : public CommandObjectParsed {
61014f1b3e8SDimitry Andric   class CommandOptions : public Options {
611f034231aSEd Maste   public:
612145449b1SDimitry Andric     CommandOptions() = default;
613f034231aSEd Maste 
614f3fbd1c0SDimitry Andric     ~CommandOptions() override = default;
615f034231aSEd Maste 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)616b76161e4SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
61714f1b3e8SDimitry Andric                           ExecutionContext *execution_context) override {
618b76161e4SDimitry Andric       Status error;
61914f1b3e8SDimitry Andric       const int short_option = GetDefinitions()[option_idx].short_option;
62014f1b3e8SDimitry Andric       switch (short_option) {
621f034231aSEd Maste       case 'l':
62214f1b3e8SDimitry Andric         if (option_arg.getAsInteger(0, start_line))
62314f1b3e8SDimitry Andric           error.SetErrorStringWithFormat("invalid line number: '%s'",
62414f1b3e8SDimitry Andric                                          option_arg.str().c_str());
625f034231aSEd Maste         break;
626f034231aSEd Maste 
627f034231aSEd Maste       case 'c':
62814f1b3e8SDimitry Andric         if (option_arg.getAsInteger(0, num_lines))
62914f1b3e8SDimitry Andric           error.SetErrorStringWithFormat("invalid line count: '%s'",
63014f1b3e8SDimitry Andric                                          option_arg.str().c_str());
631f034231aSEd Maste         break;
632f034231aSEd Maste 
633f034231aSEd Maste       case 'f':
634cfca06d7SDimitry Andric         file_name = std::string(option_arg);
635f034231aSEd Maste         break;
636f034231aSEd Maste 
637f034231aSEd Maste       case 'n':
638cfca06d7SDimitry Andric         symbol_name = std::string(option_arg);
639f034231aSEd Maste         break;
640f034231aSEd Maste 
64114f1b3e8SDimitry Andric       case 'a': {
642f73363f1SDimitry Andric         address = OptionArgParser::ToAddress(execution_context, option_arg,
64314f1b3e8SDimitry Andric                                              LLDB_INVALID_ADDRESS, &error);
64414f1b3e8SDimitry Andric       } break;
645f034231aSEd Maste       case 's':
646f034231aSEd Maste         modules.push_back(std::string(option_arg));
647f034231aSEd Maste         break;
648f034231aSEd Maste 
649f034231aSEd Maste       case 'b':
650f034231aSEd Maste         show_bp_locs = true;
651f034231aSEd Maste         break;
652f034231aSEd Maste       case 'r':
653f034231aSEd Maste         reverse = true;
654f034231aSEd Maste         break;
655b60736ecSDimitry Andric       case 'y':
656b60736ecSDimitry Andric       {
657b60736ecSDimitry Andric         OptionValueFileColonLine value;
658b60736ecSDimitry Andric         Status fcl_err = value.SetValueFromString(option_arg);
659b60736ecSDimitry Andric         if (!fcl_err.Success()) {
660b60736ecSDimitry Andric           error.SetErrorStringWithFormat(
661b60736ecSDimitry Andric               "Invalid value for file:line specifier: %s",
662b60736ecSDimitry Andric               fcl_err.AsCString());
663b60736ecSDimitry Andric         } else {
664b60736ecSDimitry Andric           file_name = value.GetFileSpec().GetPath();
665b60736ecSDimitry Andric           start_line = value.GetLineNumber();
666b60736ecSDimitry Andric           // I don't see anything useful to do with a column number, but I don't
667b60736ecSDimitry Andric           // want to complain since someone may well have cut and pasted a
668b60736ecSDimitry Andric           // listing from somewhere that included a column.
669b60736ecSDimitry Andric         }
670b60736ecSDimitry Andric       } break;
671f034231aSEd Maste       default:
672ead24645SDimitry Andric         llvm_unreachable("Unimplemented option");
673f034231aSEd Maste       }
674f034231aSEd Maste 
675f034231aSEd Maste       return error;
676f034231aSEd Maste     }
677f034231aSEd Maste 
OptionParsingStarting(ExecutionContext * execution_context)67814f1b3e8SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
679f034231aSEd Maste       file_spec.Clear();
680f034231aSEd Maste       file_name.clear();
681f034231aSEd Maste       symbol_name.clear();
682f034231aSEd Maste       address = LLDB_INVALID_ADDRESS;
683f034231aSEd Maste       start_line = 0;
684f034231aSEd Maste       num_lines = 0;
685f034231aSEd Maste       show_bp_locs = false;
686f034231aSEd Maste       reverse = false;
687f034231aSEd Maste       modules.clear();
688f034231aSEd Maste     }
689f034231aSEd Maste 
GetDefinitions()69014f1b3e8SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
691e3b55780SDimitry Andric       return llvm::ArrayRef(g_source_list_options);
692f034231aSEd Maste     }
693f3fbd1c0SDimitry Andric 
694f034231aSEd Maste     // Instance variables to hold the values for command options.
695f034231aSEd Maste     FileSpec file_spec;
696f034231aSEd Maste     std::string file_name;
697f034231aSEd Maste     std::string symbol_name;
698f034231aSEd Maste     lldb::addr_t address;
699f034231aSEd Maste     uint32_t start_line;
700f034231aSEd Maste     uint32_t num_lines;
701706b4fc4SDimitry Andric     std::vector<std::string> modules;
702f034231aSEd Maste     bool show_bp_locs;
703f034231aSEd Maste     bool reverse;
704f034231aSEd Maste   };
705f034231aSEd Maste 
706f034231aSEd Maste public:
CommandObjectSourceList(CommandInterpreter & interpreter)707f3fbd1c0SDimitry Andric   CommandObjectSourceList(CommandInterpreter &interpreter)
708f3fbd1c0SDimitry Andric       : CommandObjectParsed(interpreter, "source list",
70914f1b3e8SDimitry Andric                             "Display source code for the current target "
71014f1b3e8SDimitry Andric                             "process as specified by options.",
7116f8fc217SDimitry Andric                             nullptr, eCommandRequiresTarget) {}
712f034231aSEd Maste 
713f3fbd1c0SDimitry Andric   ~CommandObjectSourceList() override = default;
714f034231aSEd Maste 
GetOptions()71514f1b3e8SDimitry Andric   Options *GetOptions() override { return &m_options; }
716f034231aSEd Maste 
GetRepeatCommand(Args & current_command_args,uint32_t index)717e3b55780SDimitry Andric   std::optional<std::string> GetRepeatCommand(Args &current_command_args,
71814f1b3e8SDimitry Andric                                               uint32_t index) override {
719f73363f1SDimitry Andric     // This is kind of gross, but the command hasn't been parsed yet so we
720f73363f1SDimitry Andric     // can't look at the option values for this invocation...  I have to scan
721f73363f1SDimitry Andric     // the arguments directly.
72214f1b3e8SDimitry Andric     auto iter =
72314f1b3e8SDimitry Andric         llvm::find_if(current_command_args, [](const Args::ArgEntry &e) {
724ead24645SDimitry Andric           return e.ref() == "-r" || e.ref() == "--reverse";
72514f1b3e8SDimitry Andric         });
72614f1b3e8SDimitry Andric     if (iter == current_command_args.end())
727145449b1SDimitry Andric       return m_cmd_name;
72814f1b3e8SDimitry Andric 
72914f1b3e8SDimitry Andric     if (m_reverse_name.empty()) {
730f034231aSEd Maste       m_reverse_name = m_cmd_name;
731f034231aSEd Maste       m_reverse_name.append(" -r");
732f034231aSEd Maste     }
733145449b1SDimitry Andric     return m_reverse_name;
734f034231aSEd Maste   }
735f034231aSEd Maste 
736f034231aSEd Maste protected:
73714f1b3e8SDimitry Andric   struct SourceInfo {
738f034231aSEd Maste     ConstString function;
739f034231aSEd Maste     LineEntry line_entry;
740f034231aSEd Maste 
SourceInfoCommandObjectSourceList::SourceInfo7415f29bb8aSDimitry Andric     SourceInfo(ConstString name, const LineEntry &line_entry)
74214f1b3e8SDimitry Andric         : function(name), line_entry(line_entry) {}
743f034231aSEd Maste 
744145449b1SDimitry Andric     SourceInfo() = default;
745f034231aSEd Maste 
IsValidCommandObjectSourceList::SourceInfo74614f1b3e8SDimitry Andric     bool IsValid() const { return (bool)function && line_entry.IsValid(); }
747f034231aSEd Maste 
operator ==CommandObjectSourceList::SourceInfo74814f1b3e8SDimitry Andric     bool operator==(const SourceInfo &rhs) const {
749f034231aSEd Maste       return function == rhs.function &&
750ac9a064cSDimitry Andric              line_entry.original_file_sp->Equal(
751ac9a064cSDimitry Andric                  *rhs.line_entry.original_file_sp,
752ac9a064cSDimitry Andric                  SupportFile::eEqualFileSpecAndChecksumIfSet) &&
753f034231aSEd Maste              line_entry.line == rhs.line_entry.line;
754f034231aSEd Maste     }
755f034231aSEd Maste 
operator !=CommandObjectSourceList::SourceInfo75614f1b3e8SDimitry Andric     bool operator!=(const SourceInfo &rhs) const {
757f034231aSEd Maste       return function != rhs.function ||
758ac9a064cSDimitry Andric              !line_entry.original_file_sp->Equal(
759ac9a064cSDimitry Andric                  *rhs.line_entry.original_file_sp,
760ac9a064cSDimitry Andric                  SupportFile::eEqualFileSpecAndChecksumIfSet) ||
761f034231aSEd Maste              line_entry.line != rhs.line_entry.line;
762f034231aSEd Maste     }
763f034231aSEd Maste 
operator <CommandObjectSourceList::SourceInfo76414f1b3e8SDimitry Andric     bool operator<(const SourceInfo &rhs) const {
765f034231aSEd Maste       if (function.GetCString() < rhs.function.GetCString())
766f034231aSEd Maste         return true;
767ac9a064cSDimitry Andric       if (line_entry.GetFile().GetDirectory().GetCString() <
768ac9a064cSDimitry Andric           rhs.line_entry.GetFile().GetDirectory().GetCString())
769f034231aSEd Maste         return true;
770ac9a064cSDimitry Andric       if (line_entry.GetFile().GetFilename().GetCString() <
771ac9a064cSDimitry Andric           rhs.line_entry.GetFile().GetFilename().GetCString())
772f034231aSEd Maste         return true;
773f034231aSEd Maste       if (line_entry.line < rhs.line_entry.line)
774f034231aSEd Maste         return true;
775f034231aSEd Maste       return false;
776f034231aSEd Maste     }
777f034231aSEd Maste   };
778f034231aSEd Maste 
DisplayFunctionSource(const SymbolContext & sc,SourceInfo & source_info,CommandReturnObject & result)77914f1b3e8SDimitry Andric   size_t DisplayFunctionSource(const SymbolContext &sc, SourceInfo &source_info,
78014f1b3e8SDimitry Andric                                CommandReturnObject &result) {
78114f1b3e8SDimitry Andric     if (!source_info.IsValid()) {
782f034231aSEd Maste       source_info.function = sc.GetFunctionName();
783f034231aSEd Maste       source_info.line_entry = sc.GetFunctionStartLineEntry();
784f034231aSEd Maste     }
785f034231aSEd Maste 
78614f1b3e8SDimitry Andric     if (sc.function) {
787f034231aSEd Maste       Target *target = m_exe_ctx.GetTargetPtr();
788f034231aSEd Maste 
789f034231aSEd Maste       FileSpec start_file;
790f034231aSEd Maste       uint32_t start_line;
791f034231aSEd Maste       uint32_t end_line;
792f034231aSEd Maste       FileSpec end_file;
793f034231aSEd Maste 
79414f1b3e8SDimitry Andric       if (sc.block == nullptr) {
795f034231aSEd Maste         // Not an inlined function
796f034231aSEd Maste         sc.function->GetStartLineSourceInfo(start_file, start_line);
79714f1b3e8SDimitry Andric         if (start_line == 0) {
79814f1b3e8SDimitry Andric           result.AppendErrorWithFormat("Could not find line information for "
79914f1b3e8SDimitry Andric                                        "start of function: \"%s\".\n",
80014f1b3e8SDimitry Andric                                        source_info.function.GetCString());
801f034231aSEd Maste           return 0;
802f034231aSEd Maste         }
803f034231aSEd Maste         sc.function->GetEndLineSourceInfo(end_file, end_line);
80414f1b3e8SDimitry Andric       } else {
805f034231aSEd Maste         // We have an inlined function
806ac9a064cSDimitry Andric         start_file = source_info.line_entry.GetFile();
807f034231aSEd Maste         start_line = source_info.line_entry.line;
808f034231aSEd Maste         end_line = start_line + m_options.num_lines;
809f034231aSEd Maste       }
810f034231aSEd Maste 
81114f1b3e8SDimitry Andric       // This is a little hacky, but the first line table entry for a function
812f73363f1SDimitry Andric       // points to the "{" that starts the function block.  It would be nice to
813f73363f1SDimitry Andric       // actually get the function declaration in there too.  So back up a bit,
814f73363f1SDimitry Andric       // but not further than what you're going to display.
815f034231aSEd Maste       uint32_t extra_lines;
816f034231aSEd Maste       if (m_options.num_lines >= 10)
817f034231aSEd Maste         extra_lines = 5;
818f034231aSEd Maste       else
819f034231aSEd Maste         extra_lines = m_options.num_lines / 2;
820f034231aSEd Maste       uint32_t line_no;
821f034231aSEd Maste       if (start_line <= extra_lines)
822f034231aSEd Maste         line_no = 1;
823f034231aSEd Maste       else
824f034231aSEd Maste         line_no = start_line - extra_lines;
825f034231aSEd Maste 
82614f1b3e8SDimitry Andric       // For fun, if the function is shorter than the number of lines we're
827f73363f1SDimitry Andric       // supposed to display, only display the function...
82814f1b3e8SDimitry Andric       if (end_line != 0) {
829f034231aSEd Maste         if (m_options.num_lines > end_line - line_no)
830f034231aSEd Maste           m_options.num_lines = end_line - line_no + extra_lines;
831f034231aSEd Maste       }
832f034231aSEd Maste 
833f034231aSEd Maste       m_breakpoint_locations.Clear();
834f034231aSEd Maste 
83514f1b3e8SDimitry Andric       if (m_options.show_bp_locs) {
836f034231aSEd Maste         const bool show_inlines = true;
837f034231aSEd Maste         m_breakpoint_locations.Reset(start_file, 0, show_inlines);
83814f1b3e8SDimitry Andric         SearchFilterForUnconstrainedSearches target_search_filter(
83914f1b3e8SDimitry Andric             m_exe_ctx.GetTargetSP());
840f034231aSEd Maste         target_search_filter.Search(m_breakpoint_locations);
841f034231aSEd Maste       }
842f034231aSEd Maste 
84314f1b3e8SDimitry Andric       result.AppendMessageWithFormat("File: %s\n",
84414f1b3e8SDimitry Andric                                      start_file.GetPath().c_str());
84514f1b3e8SDimitry Andric       // We don't care about the column here.
84614f1b3e8SDimitry Andric       const uint32_t column = 0;
84714f1b3e8SDimitry Andric       return target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
848ef5d0b5eSDimitry Andric           start_file, line_no, column, 0, m_options.num_lines, "",
84914f1b3e8SDimitry Andric           &result.GetOutputStream(), GetBreakpointLocations());
85014f1b3e8SDimitry Andric     } else {
85114f1b3e8SDimitry Andric       result.AppendErrorWithFormat(
85214f1b3e8SDimitry Andric           "Could not find function info for: \"%s\".\n",
85314f1b3e8SDimitry Andric           m_options.symbol_name.c_str());
854f034231aSEd Maste     }
855f034231aSEd Maste     return 0;
856f034231aSEd Maste   }
857f034231aSEd Maste 
858f73363f1SDimitry Andric   // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols
859f73363f1SDimitry Andric   // functions "take a possibly empty vector of strings which are names of
860f73363f1SDimitry Andric   // modules, and run the two search functions on the subset of the full module
861f73363f1SDimitry Andric   // list that matches the strings in the input vector". If we wanted to put
862f73363f1SDimitry Andric   // these somewhere, there should probably be a module-filter-list that can be
863f73363f1SDimitry Andric   // passed to the various ModuleList::Find* calls, which would either be a
864f73363f1SDimitry Andric   // vector of string names or a ModuleSpecList.
FindMatchingFunctions(Target * target,ConstString name,SymbolContextList & sc_list)865ead24645SDimitry Andric   void FindMatchingFunctions(Target *target, ConstString name,
86614f1b3e8SDimitry Andric                              SymbolContextList &sc_list) {
867f034231aSEd Maste     // Displaying the source for a symbol:
868f034231aSEd Maste     if (m_options.num_lines == 0)
869f034231aSEd Maste       m_options.num_lines = 10;
870f034231aSEd Maste 
871c0981da4SDimitry Andric     ModuleFunctionSearchOptions function_options;
872c0981da4SDimitry Andric     function_options.include_symbols = true;
873c0981da4SDimitry Andric     function_options.include_inlines = false;
874c0981da4SDimitry Andric 
875f034231aSEd Maste     const size_t num_modules = m_options.modules.size();
87614f1b3e8SDimitry Andric     if (num_modules > 0) {
877f034231aSEd Maste       ModuleList matching_modules;
87814f1b3e8SDimitry Andric       for (size_t i = 0; i < num_modules; ++i) {
87994994d37SDimitry Andric         FileSpec module_file_spec(m_options.modules[i]);
88014f1b3e8SDimitry Andric         if (module_file_spec) {
881f034231aSEd Maste           ModuleSpec module_spec(module_file_spec);
882f034231aSEd Maste           matching_modules.Clear();
883f034231aSEd Maste           target->GetImages().FindModules(module_spec, matching_modules);
884c0981da4SDimitry Andric 
885706b4fc4SDimitry Andric           matching_modules.FindFunctions(name, eFunctionNameTypeAuto,
886c0981da4SDimitry Andric                                          function_options, sc_list);
887f034231aSEd Maste         }
888f034231aSEd Maste       }
88914f1b3e8SDimitry Andric     } else {
890ead24645SDimitry Andric       target->GetImages().FindFunctions(name, eFunctionNameTypeAuto,
891c0981da4SDimitry Andric                                         function_options, sc_list);
892f034231aSEd Maste     }
893f034231aSEd Maste   }
894f034231aSEd Maste 
FindMatchingFunctionSymbols(Target * target,ConstString name,SymbolContextList & sc_list)895ead24645SDimitry Andric   void FindMatchingFunctionSymbols(Target *target, ConstString name,
89614f1b3e8SDimitry Andric                                    SymbolContextList &sc_list) {
897f034231aSEd Maste     const size_t num_modules = m_options.modules.size();
89814f1b3e8SDimitry Andric     if (num_modules > 0) {
899f034231aSEd Maste       ModuleList matching_modules;
90014f1b3e8SDimitry Andric       for (size_t i = 0; i < num_modules; ++i) {
90194994d37SDimitry Andric         FileSpec module_file_spec(m_options.modules[i]);
90214f1b3e8SDimitry Andric         if (module_file_spec) {
903f034231aSEd Maste           ModuleSpec module_spec(module_file_spec);
904f034231aSEd Maste           matching_modules.Clear();
905f034231aSEd Maste           target->GetImages().FindModules(module_spec, matching_modules);
906ead24645SDimitry Andric           matching_modules.FindFunctionSymbols(name, eFunctionNameTypeAuto,
907ead24645SDimitry Andric                                                sc_list);
908f034231aSEd Maste         }
909f034231aSEd Maste       }
91014f1b3e8SDimitry Andric     } else {
911ead24645SDimitry Andric       target->GetImages().FindFunctionSymbols(name, eFunctionNameTypeAuto,
912ead24645SDimitry Andric                                               sc_list);
913f034231aSEd Maste     }
914f034231aSEd Maste   }
915f034231aSEd Maste 
DoExecute(Args & command,CommandReturnObject & result)916b1c73532SDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
917f034231aSEd Maste     Target *target = m_exe_ctx.GetTargetPtr();
918f034231aSEd Maste 
91914f1b3e8SDimitry Andric     if (!m_options.symbol_name.empty()) {
920f034231aSEd Maste       SymbolContextList sc_list;
921f034231aSEd Maste       ConstString name(m_options.symbol_name.c_str());
922f034231aSEd Maste 
923f034231aSEd Maste       // Displaying the source for a symbol. Search for function named name.
924ead24645SDimitry Andric       FindMatchingFunctions(target, name, sc_list);
9257fa27ce4SDimitry Andric       if (sc_list.GetSize() == 0) {
92614f1b3e8SDimitry Andric         // If we didn't find any functions with that name, try searching for
927f73363f1SDimitry Andric         // symbols that line up exactly with function addresses.
928f034231aSEd Maste         SymbolContextList sc_list_symbols;
92914f1b3e8SDimitry Andric         FindMatchingFunctionSymbols(target, name, sc_list_symbols);
9307fa27ce4SDimitry Andric         for (const SymbolContext &sc : sc_list_symbols) {
93114f1b3e8SDimitry Andric           if (sc.symbol && sc.symbol->ValueIsAddress()) {
9325e95aa85SEd Maste             const Address &base_address = sc.symbol->GetAddressRef();
933f034231aSEd Maste             Function *function = base_address.CalculateSymbolContextFunction();
93414f1b3e8SDimitry Andric             if (function) {
935f034231aSEd Maste               sc_list.Append(SymbolContext(function));
936f034231aSEd Maste               break;
937f034231aSEd Maste             }
938f034231aSEd Maste           }
939f034231aSEd Maste         }
940f034231aSEd Maste       }
941f034231aSEd Maste 
9427fa27ce4SDimitry Andric       if (sc_list.GetSize() == 0) {
94314f1b3e8SDimitry Andric         result.AppendErrorWithFormat("Could not find function named: \"%s\".\n",
94414f1b3e8SDimitry Andric                                      m_options.symbol_name.c_str());
945b1c73532SDimitry Andric         return;
946f034231aSEd Maste       }
947f034231aSEd Maste 
948f034231aSEd Maste       std::set<SourceInfo> source_match_set;
949f034231aSEd Maste       bool displayed_something = false;
9507fa27ce4SDimitry Andric       for (const SymbolContext &sc : sc_list) {
951f034231aSEd Maste         SourceInfo source_info(sc.GetFunctionName(),
952f034231aSEd Maste                                sc.GetFunctionStartLineEntry());
9537fa27ce4SDimitry Andric         if (source_info.IsValid() &&
9547fa27ce4SDimitry Andric             source_match_set.find(source_info) == source_match_set.end()) {
955f034231aSEd Maste           source_match_set.insert(source_info);
956f034231aSEd Maste           if (DisplayFunctionSource(sc, source_info, result))
957f034231aSEd Maste             displayed_something = true;
958f034231aSEd Maste         }
959f034231aSEd Maste       }
960f034231aSEd Maste       if (displayed_something)
961f034231aSEd Maste         result.SetStatus(eReturnStatusSuccessFinishResult);
962f034231aSEd Maste       else
963f034231aSEd Maste         result.SetStatus(eReturnStatusFailed);
964b1c73532SDimitry Andric       return;
96514f1b3e8SDimitry Andric     } else if (m_options.address != LLDB_INVALID_ADDRESS) {
966f034231aSEd Maste       Address so_addr;
967f034231aSEd Maste       StreamString error_strm;
968f034231aSEd Maste       SymbolContextList sc_list;
969f034231aSEd Maste 
97014f1b3e8SDimitry Andric       if (target->GetSectionLoadList().IsEmpty()) {
971f73363f1SDimitry Andric         // The target isn't loaded yet, we need to lookup the file address in
972f73363f1SDimitry Andric         // all modules
973f034231aSEd Maste         const ModuleList &module_list = target->GetImages();
974f034231aSEd Maste         const size_t num_modules = module_list.GetSize();
97514f1b3e8SDimitry Andric         for (size_t i = 0; i < num_modules; ++i) {
976f034231aSEd Maste           ModuleSP module_sp(module_list.GetModuleAtIndex(i));
97714f1b3e8SDimitry Andric           if (module_sp &&
97814f1b3e8SDimitry Andric               module_sp->ResolveFileAddress(m_options.address, so_addr)) {
979f034231aSEd Maste             SymbolContext sc;
980f034231aSEd Maste             sc.Clear(true);
98114f1b3e8SDimitry Andric             if (module_sp->ResolveSymbolContextForAddress(
98214f1b3e8SDimitry Andric                     so_addr, eSymbolContextEverything, sc) &
98314f1b3e8SDimitry Andric                 eSymbolContextLineEntry)
984f034231aSEd Maste               sc_list.Append(sc);
985f034231aSEd Maste           }
986f034231aSEd Maste         }
987f034231aSEd Maste 
98814f1b3e8SDimitry Andric         if (sc_list.GetSize() == 0) {
98914f1b3e8SDimitry Andric           result.AppendErrorWithFormat(
99014f1b3e8SDimitry Andric               "no modules have source information for file address 0x%" PRIx64
99114f1b3e8SDimitry Andric               ".\n",
992f034231aSEd Maste               m_options.address);
993b1c73532SDimitry Andric           return;
994f034231aSEd Maste         }
99514f1b3e8SDimitry Andric       } else {
996f73363f1SDimitry Andric         // The target has some things loaded, resolve this address to a compile
997f73363f1SDimitry Andric         // unit + file + line and display
99814f1b3e8SDimitry Andric         if (target->GetSectionLoadList().ResolveLoadAddress(m_options.address,
99914f1b3e8SDimitry Andric                                                             so_addr)) {
1000f034231aSEd Maste           ModuleSP module_sp(so_addr.GetModule());
100114f1b3e8SDimitry Andric           if (module_sp) {
1002f034231aSEd Maste             SymbolContext sc;
1003f034231aSEd Maste             sc.Clear(true);
100414f1b3e8SDimitry Andric             if (module_sp->ResolveSymbolContextForAddress(
100514f1b3e8SDimitry Andric                     so_addr, eSymbolContextEverything, sc) &
100614f1b3e8SDimitry Andric                 eSymbolContextLineEntry) {
1007f034231aSEd Maste               sc_list.Append(sc);
100814f1b3e8SDimitry Andric             } else {
100914f1b3e8SDimitry Andric               so_addr.Dump(&error_strm, nullptr,
101014f1b3e8SDimitry Andric                            Address::DumpStyleModuleWithFileAddress);
101114f1b3e8SDimitry Andric               result.AppendErrorWithFormat("address resolves to %s, but there "
101214f1b3e8SDimitry Andric                                            "is no line table information "
101314f1b3e8SDimitry Andric                                            "available for this address.\n",
1014f034231aSEd Maste                                            error_strm.GetData());
1015b1c73532SDimitry Andric               return;
1016f034231aSEd Maste             }
1017f034231aSEd Maste           }
1018f034231aSEd Maste         }
1019f034231aSEd Maste 
102014f1b3e8SDimitry Andric         if (sc_list.GetSize() == 0) {
102114f1b3e8SDimitry Andric           result.AppendErrorWithFormat(
102214f1b3e8SDimitry Andric               "no modules contain load address 0x%" PRIx64 ".\n",
102314f1b3e8SDimitry Andric               m_options.address);
1024b1c73532SDimitry Andric           return;
1025f034231aSEd Maste         }
1026f034231aSEd Maste       }
10277fa27ce4SDimitry Andric       for (const SymbolContext &sc : sc_list) {
102814f1b3e8SDimitry Andric         if (sc.comp_unit) {
102914f1b3e8SDimitry Andric           if (m_options.show_bp_locs) {
1030f034231aSEd Maste             m_breakpoint_locations.Clear();
1031f034231aSEd Maste             const bool show_inlines = true;
1032706b4fc4SDimitry Andric             m_breakpoint_locations.Reset(sc.comp_unit->GetPrimaryFile(), 0,
1033706b4fc4SDimitry Andric                                          show_inlines);
103414f1b3e8SDimitry Andric             SearchFilterForUnconstrainedSearches target_search_filter(
103514f1b3e8SDimitry Andric                 target->shared_from_this());
1036f034231aSEd Maste             target_search_filter.Search(m_breakpoint_locations);
1037f034231aSEd Maste           }
1038f034231aSEd Maste 
1039f034231aSEd Maste           bool show_fullpaths = true;
1040f034231aSEd Maste           bool show_module = true;
1041f034231aSEd Maste           bool show_inlined_frames = true;
1042205afe67SEd Maste           const bool show_function_arguments = true;
10435e95aa85SEd Maste           const bool show_function_name = true;
1044f034231aSEd Maste           sc.DumpStopContext(&result.GetOutputStream(),
1045f034231aSEd Maste                              m_exe_ctx.GetBestExecutionContextScope(),
1046f034231aSEd Maste                              sc.line_entry.range.GetBaseAddress(),
104714f1b3e8SDimitry Andric                              show_fullpaths, show_module, show_inlined_frames,
104814f1b3e8SDimitry Andric                              show_function_arguments, show_function_name);
1049f034231aSEd Maste           result.GetOutputStream().EOL();
1050f034231aSEd Maste 
1051f034231aSEd Maste           if (m_options.num_lines == 0)
1052f034231aSEd Maste             m_options.num_lines = 10;
1053f034231aSEd Maste 
105414f1b3e8SDimitry Andric           size_t lines_to_back_up =
105514f1b3e8SDimitry Andric               m_options.num_lines >= 10 ? 5 : m_options.num_lines / 2;
1056f034231aSEd Maste 
105714f1b3e8SDimitry Andric           const uint32_t column =
10585f29bb8aSDimitry Andric               (GetDebugger().GetStopShowColumn() != eStopShowColumnNone)
105914f1b3e8SDimitry Andric                   ? sc.line_entry.column
106014f1b3e8SDimitry Andric                   : 0;
106114f1b3e8SDimitry Andric           target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
1062706b4fc4SDimitry Andric               sc.comp_unit->GetPrimaryFile(), sc.line_entry.line, column,
1063706b4fc4SDimitry Andric               lines_to_back_up, m_options.num_lines - lines_to_back_up, "->",
106414f1b3e8SDimitry Andric               &result.GetOutputStream(), GetBreakpointLocations());
1065f034231aSEd Maste           result.SetStatus(eReturnStatusSuccessFinishResult);
1066f034231aSEd Maste         }
1067f034231aSEd Maste       }
106814f1b3e8SDimitry Andric     } else if (m_options.file_name.empty()) {
1069f73363f1SDimitry Andric       // Last valid source manager context, or the current frame if no valid
1070f73363f1SDimitry Andric       // last context in source manager. One little trick here, if you type the
1071f73363f1SDimitry Andric       // exact same list command twice in a row, it is more likely because you
1072f73363f1SDimitry Andric       // typed it once, then typed it again
107314f1b3e8SDimitry Andric       if (m_options.start_line == 0) {
107414f1b3e8SDimitry Andric         if (target->GetSourceManager().DisplayMoreWithLineNumbers(
107514f1b3e8SDimitry Andric                 &result.GetOutputStream(), m_options.num_lines,
107614f1b3e8SDimitry Andric                 m_options.reverse, GetBreakpointLocations())) {
1077f034231aSEd Maste           result.SetStatus(eReturnStatusSuccessFinishResult);
1078f034231aSEd Maste         }
107914f1b3e8SDimitry Andric       } else {
1080f034231aSEd Maste         if (m_options.num_lines == 0)
1081f034231aSEd Maste           m_options.num_lines = 10;
1082f034231aSEd Maste 
108314f1b3e8SDimitry Andric         if (m_options.show_bp_locs) {
108414f1b3e8SDimitry Andric           SourceManager::FileSP last_file_sp(
108514f1b3e8SDimitry Andric               target->GetSourceManager().GetLastFile());
108614f1b3e8SDimitry Andric           if (last_file_sp) {
1087f034231aSEd Maste             const bool show_inlines = true;
108814f1b3e8SDimitry Andric             m_breakpoint_locations.Reset(last_file_sp->GetFileSpec(), 0,
108914f1b3e8SDimitry Andric                                          show_inlines);
109014f1b3e8SDimitry Andric             SearchFilterForUnconstrainedSearches target_search_filter(
109114f1b3e8SDimitry Andric                 target->shared_from_this());
1092f034231aSEd Maste             target_search_filter.Search(m_breakpoint_locations);
1093f034231aSEd Maste           }
109414f1b3e8SDimitry Andric         } else
1095f034231aSEd Maste           m_breakpoint_locations.Clear();
1096f034231aSEd Maste 
109714f1b3e8SDimitry Andric         const uint32_t column = 0;
109814f1b3e8SDimitry Andric         if (target->GetSourceManager()
109914f1b3e8SDimitry Andric                 .DisplaySourceLinesWithLineNumbersUsingLastFile(
1100f034231aSEd Maste                     m_options.start_line, // Line to display
1101f034231aSEd Maste                     m_options.num_lines,  // Lines after line to
1102f034231aSEd Maste                     UINT32_MAX,           // Don't mark "line"
110314f1b3e8SDimitry Andric                     column,
1104f034231aSEd Maste                     "", // Don't mark "line"
110514f1b3e8SDimitry Andric                     &result.GetOutputStream(), GetBreakpointLocations())) {
1106f034231aSEd Maste           result.SetStatus(eReturnStatusSuccessFinishResult);
1107f034231aSEd Maste         }
1108f034231aSEd Maste       }
110914f1b3e8SDimitry Andric     } else {
1110f034231aSEd Maste       const char *filename = m_options.file_name.c_str();
1111f034231aSEd Maste 
1112f034231aSEd Maste       bool check_inlines = false;
1113f034231aSEd Maste       SymbolContextList sc_list;
1114f034231aSEd Maste       size_t num_matches = 0;
1115f034231aSEd Maste 
111614f1b3e8SDimitry Andric       if (!m_options.modules.empty()) {
1117f034231aSEd Maste         ModuleList matching_modules;
111814f1b3e8SDimitry Andric         for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) {
111994994d37SDimitry Andric           FileSpec module_file_spec(m_options.modules[i]);
112014f1b3e8SDimitry Andric           if (module_file_spec) {
1121f034231aSEd Maste             ModuleSpec module_spec(module_file_spec);
1122f034231aSEd Maste             matching_modules.Clear();
1123f034231aSEd Maste             target->GetImages().FindModules(module_spec, matching_modules);
112414f1b3e8SDimitry Andric             num_matches += matching_modules.ResolveSymbolContextForFilePath(
112514f1b3e8SDimitry Andric                 filename, 0, check_inlines,
112694994d37SDimitry Andric                 SymbolContextItem(eSymbolContextModule |
112794994d37SDimitry Andric                                   eSymbolContextCompUnit),
112894994d37SDimitry Andric                 sc_list);
1129f034231aSEd Maste           }
1130f034231aSEd Maste         }
113114f1b3e8SDimitry Andric       } else {
113214f1b3e8SDimitry Andric         num_matches = target->GetImages().ResolveSymbolContextForFilePath(
113314f1b3e8SDimitry Andric             filename, 0, check_inlines,
113414f1b3e8SDimitry Andric             eSymbolContextModule | eSymbolContextCompUnit, sc_list);
1135f034231aSEd Maste       }
1136f034231aSEd Maste 
113714f1b3e8SDimitry Andric       if (num_matches == 0) {
1138f034231aSEd Maste         result.AppendErrorWithFormat("Could not find source file \"%s\".\n",
1139f034231aSEd Maste                                      m_options.file_name.c_str());
1140b1c73532SDimitry Andric         return;
1141f034231aSEd Maste       }
1142f034231aSEd Maste 
114314f1b3e8SDimitry Andric       if (num_matches > 1) {
1144f034231aSEd Maste         bool got_multiple = false;
1145706b4fc4SDimitry Andric         CompileUnit *test_cu = nullptr;
1146f034231aSEd Maste 
11477fa27ce4SDimitry Andric         for (const SymbolContext &sc : sc_list) {
114814f1b3e8SDimitry Andric           if (sc.comp_unit) {
1149706b4fc4SDimitry Andric             if (test_cu) {
1150706b4fc4SDimitry Andric               if (test_cu != sc.comp_unit)
1151f034231aSEd Maste                 got_multiple = true;
1152f034231aSEd Maste               break;
115314f1b3e8SDimitry Andric             } else
1154706b4fc4SDimitry Andric               test_cu = sc.comp_unit;
1155f034231aSEd Maste           }
1156f034231aSEd Maste         }
115714f1b3e8SDimitry Andric         if (got_multiple) {
115814f1b3e8SDimitry Andric           result.AppendErrorWithFormat(
115914f1b3e8SDimitry Andric               "Multiple source files found matching: \"%s.\"\n",
1160f034231aSEd Maste               m_options.file_name.c_str());
1161b1c73532SDimitry Andric           return;
1162f034231aSEd Maste         }
1163f034231aSEd Maste       }
1164f034231aSEd Maste 
1165f034231aSEd Maste       SymbolContext sc;
116614f1b3e8SDimitry Andric       if (sc_list.GetContextAtIndex(0, sc)) {
116714f1b3e8SDimitry Andric         if (sc.comp_unit) {
116814f1b3e8SDimitry Andric           if (m_options.show_bp_locs) {
1169f034231aSEd Maste             const bool show_inlines = true;
1170706b4fc4SDimitry Andric             m_breakpoint_locations.Reset(sc.comp_unit->GetPrimaryFile(), 0,
1171706b4fc4SDimitry Andric                                          show_inlines);
117214f1b3e8SDimitry Andric             SearchFilterForUnconstrainedSearches target_search_filter(
117314f1b3e8SDimitry Andric                 target->shared_from_this());
1174f034231aSEd Maste             target_search_filter.Search(m_breakpoint_locations);
117514f1b3e8SDimitry Andric           } else
1176f034231aSEd Maste             m_breakpoint_locations.Clear();
1177f034231aSEd Maste 
1178f034231aSEd Maste           if (m_options.num_lines == 0)
1179f034231aSEd Maste             m_options.num_lines = 10;
118014f1b3e8SDimitry Andric           const uint32_t column = 0;
118114f1b3e8SDimitry Andric           target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
1182706b4fc4SDimitry Andric               sc.comp_unit->GetPrimaryFile(), m_options.start_line, column, 0,
1183706b4fc4SDimitry Andric               m_options.num_lines, "", &result.GetOutputStream(),
1184706b4fc4SDimitry Andric               GetBreakpointLocations());
1185f034231aSEd Maste 
1186f034231aSEd Maste           result.SetStatus(eReturnStatusSuccessFinishResult);
118714f1b3e8SDimitry Andric         } else {
1188f034231aSEd Maste           result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n",
1189f034231aSEd Maste                                        m_options.file_name.c_str());
1190f034231aSEd Maste         }
1191f034231aSEd Maste       }
1192f034231aSEd Maste     }
1193f034231aSEd Maste   }
1194f034231aSEd Maste 
GetBreakpointLocations()119514f1b3e8SDimitry Andric   const SymbolContextList *GetBreakpointLocations() {
1196f034231aSEd Maste     if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0)
1197f034231aSEd Maste       return &m_breakpoint_locations.GetFileLineMatches();
1198f3fbd1c0SDimitry Andric     return nullptr;
1199f034231aSEd Maste   }
1200f3fbd1c0SDimitry Andric 
1201f034231aSEd Maste   CommandOptions m_options;
1202f034231aSEd Maste   FileLineResolver m_breakpoint_locations;
1203f034231aSEd Maste   std::string m_reverse_name;
1204f034231aSEd Maste };
1205f034231aSEd Maste 
12067fa27ce4SDimitry Andric class CommandObjectSourceCacheDump : public CommandObjectParsed {
12077fa27ce4SDimitry Andric public:
CommandObjectSourceCacheDump(CommandInterpreter & interpreter)12087fa27ce4SDimitry Andric   CommandObjectSourceCacheDump(CommandInterpreter &interpreter)
12097fa27ce4SDimitry Andric       : CommandObjectParsed(interpreter, "source cache dump",
12107fa27ce4SDimitry Andric                             "Dump the state of the source code cache. Intended "
12117fa27ce4SDimitry Andric                             "to be used for debugging LLDB itself.",
12127fa27ce4SDimitry Andric                             nullptr) {}
12137fa27ce4SDimitry Andric 
12147fa27ce4SDimitry Andric   ~CommandObjectSourceCacheDump() override = default;
12157fa27ce4SDimitry Andric 
12167fa27ce4SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)1217b1c73532SDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
12187fa27ce4SDimitry Andric     // Dump the debugger source cache.
12197fa27ce4SDimitry Andric     result.GetOutputStream() << "Debugger Source File Cache\n";
12207fa27ce4SDimitry Andric     SourceManager::SourceFileCache &cache = GetDebugger().GetSourceFileCache();
12217fa27ce4SDimitry Andric     cache.Dump(result.GetOutputStream());
12227fa27ce4SDimitry Andric 
12237fa27ce4SDimitry Andric     // Dump the process source cache.
12247fa27ce4SDimitry Andric     if (ProcessSP process_sp = m_exe_ctx.GetProcessSP()) {
12257fa27ce4SDimitry Andric       result.GetOutputStream() << "\nProcess Source File Cache\n";
12267fa27ce4SDimitry Andric       SourceManager::SourceFileCache &cache = process_sp->GetSourceFileCache();
12277fa27ce4SDimitry Andric       cache.Dump(result.GetOutputStream());
12287fa27ce4SDimitry Andric     }
12297fa27ce4SDimitry Andric 
12307fa27ce4SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
12317fa27ce4SDimitry Andric   }
12327fa27ce4SDimitry Andric };
12337fa27ce4SDimitry Andric 
12347fa27ce4SDimitry Andric class CommandObjectSourceCacheClear : public CommandObjectParsed {
12357fa27ce4SDimitry Andric public:
CommandObjectSourceCacheClear(CommandInterpreter & interpreter)12367fa27ce4SDimitry Andric   CommandObjectSourceCacheClear(CommandInterpreter &interpreter)
12377fa27ce4SDimitry Andric       : CommandObjectParsed(interpreter, "source cache clear",
12387fa27ce4SDimitry Andric                             "Clear the source code cache.\n", nullptr) {}
12397fa27ce4SDimitry Andric 
12407fa27ce4SDimitry Andric   ~CommandObjectSourceCacheClear() override = default;
12417fa27ce4SDimitry Andric 
12427fa27ce4SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)1243b1c73532SDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
12447fa27ce4SDimitry Andric     // Clear the debugger cache.
12457fa27ce4SDimitry Andric     SourceManager::SourceFileCache &cache = GetDebugger().GetSourceFileCache();
12467fa27ce4SDimitry Andric     cache.Clear();
12477fa27ce4SDimitry Andric 
12487fa27ce4SDimitry Andric     // Clear the process cache.
12497fa27ce4SDimitry Andric     if (ProcessSP process_sp = m_exe_ctx.GetProcessSP())
12507fa27ce4SDimitry Andric       process_sp->GetSourceFileCache().Clear();
12517fa27ce4SDimitry Andric 
12527fa27ce4SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
12537fa27ce4SDimitry Andric   }
12547fa27ce4SDimitry Andric };
12557fa27ce4SDimitry Andric 
12567fa27ce4SDimitry Andric class CommandObjectSourceCache : public CommandObjectMultiword {
12577fa27ce4SDimitry Andric public:
CommandObjectSourceCache(CommandInterpreter & interpreter)12587fa27ce4SDimitry Andric   CommandObjectSourceCache(CommandInterpreter &interpreter)
12597fa27ce4SDimitry Andric       : CommandObjectMultiword(interpreter, "source cache",
12607fa27ce4SDimitry Andric                                "Commands for managing the source code cache.",
12617fa27ce4SDimitry Andric                                "source cache <sub-command>") {
12627fa27ce4SDimitry Andric     LoadSubCommand(
12637fa27ce4SDimitry Andric         "dump", CommandObjectSP(new CommandObjectSourceCacheDump(interpreter)));
12647fa27ce4SDimitry Andric     LoadSubCommand("clear", CommandObjectSP(new CommandObjectSourceCacheClear(
12657fa27ce4SDimitry Andric                                 interpreter)));
12667fa27ce4SDimitry Andric   }
12677fa27ce4SDimitry Andric 
12687fa27ce4SDimitry Andric   ~CommandObjectSourceCache() override = default;
12697fa27ce4SDimitry Andric 
12707fa27ce4SDimitry Andric private:
12717fa27ce4SDimitry Andric   CommandObjectSourceCache(const CommandObjectSourceCache &) = delete;
12727fa27ce4SDimitry Andric   const CommandObjectSourceCache &
12737fa27ce4SDimitry Andric   operator=(const CommandObjectSourceCache &) = delete;
12747fa27ce4SDimitry Andric };
12757fa27ce4SDimitry Andric 
1276f034231aSEd Maste #pragma mark CommandObjectMultiwordSource
1277f034231aSEd Maste // CommandObjectMultiwordSource
1278f034231aSEd Maste 
CommandObjectMultiwordSource(CommandInterpreter & interpreter)127914f1b3e8SDimitry Andric CommandObjectMultiwordSource::CommandObjectMultiwordSource(
128014f1b3e8SDimitry Andric     CommandInterpreter &interpreter)
1281706b4fc4SDimitry Andric     : CommandObjectMultiword(interpreter, "source",
1282706b4fc4SDimitry Andric                              "Commands for examining "
128314f1b3e8SDimitry Andric                              "source code described by "
128414f1b3e8SDimitry Andric                              "debug information for the "
128514f1b3e8SDimitry Andric                              "current target process.",
128614f1b3e8SDimitry Andric                              "source <subcommand> [<subcommand-options>]") {
128714f1b3e8SDimitry Andric   LoadSubCommand("info",
128814f1b3e8SDimitry Andric                  CommandObjectSP(new CommandObjectSourceInfo(interpreter)));
128914f1b3e8SDimitry Andric   LoadSubCommand("list",
129014f1b3e8SDimitry Andric                  CommandObjectSP(new CommandObjectSourceList(interpreter)));
12917fa27ce4SDimitry Andric   LoadSubCommand("cache",
12927fa27ce4SDimitry Andric                  CommandObjectSP(new CommandObjectSourceCache(interpreter)));
1293f034231aSEd Maste }
1294f034231aSEd Maste 
1295f3fbd1c0SDimitry Andric CommandObjectMultiwordSource::~CommandObjectMultiwordSource() = default;
1296