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 ¤t_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