1ac7ddfbfSEd Maste //===-- CommandObjectSource.cpp ---------------------------------*- C++ -*-===//
2ac7ddfbfSEd Maste //
3ac7ddfbfSEd Maste // The LLVM Compiler Infrastructure
4ac7ddfbfSEd Maste //
5ac7ddfbfSEd Maste // This file is distributed under the University of Illinois Open Source
6ac7ddfbfSEd Maste // License. See LICENSE.TXT for details.
7ac7ddfbfSEd Maste //
8ac7ddfbfSEd Maste //===----------------------------------------------------------------------===//
9ac7ddfbfSEd Maste
10ac7ddfbfSEd Maste #include "CommandObjectSource.h"
11ac7ddfbfSEd Maste
12ac7ddfbfSEd Maste #include "lldb/Core/Debugger.h"
13ac7ddfbfSEd Maste #include "lldb/Core/FileLineResolver.h"
14ac7ddfbfSEd Maste #include "lldb/Core/Module.h"
15ac7ddfbfSEd Maste #include "lldb/Core/ModuleSpec.h"
16ac7ddfbfSEd Maste #include "lldb/Core/SourceManager.h"
17f678e45dSDimitry Andric #include "lldb/Host/OptionParser.h"
18435933ddSDimitry Andric #include "lldb/Interpreter/CommandCompletions.h"
19435933ddSDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
20435933ddSDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
214ba319b5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
22435933ddSDimitry Andric #include "lldb/Interpreter/Options.h"
23ac7ddfbfSEd Maste #include "lldb/Symbol/CompileUnit.h"
24ac7ddfbfSEd Maste #include "lldb/Symbol/Function.h"
25ac7ddfbfSEd Maste #include "lldb/Symbol/Symbol.h"
26ac7ddfbfSEd Maste #include "lldb/Target/Process.h"
2712b93ac6SEd Maste #include "lldb/Target/SectionLoadList.h"
28a1bd240cSDimitry Andric #include "lldb/Target/StackFrame.h"
29ac7ddfbfSEd Maste #include "lldb/Target/TargetList.h"
30f678e45dSDimitry Andric #include "lldb/Utility/FileSpec.h"
31ac7ddfbfSEd Maste
32ac7ddfbfSEd Maste using namespace lldb;
33ac7ddfbfSEd Maste using namespace lldb_private;
34ac7ddfbfSEd Maste
35a1bd240cSDimitry Andric #pragma mark CommandObjectSourceInfo
36a1bd240cSDimitry Andric //----------------------------------------------------------------------
37a1bd240cSDimitry Andric // CommandObjectSourceInfo - debug line entries dumping command
38a1bd240cSDimitry Andric //----------------------------------------------------------------------
39ac7ddfbfSEd Maste
40*b5893f02SDimitry Andric static constexpr OptionDefinition g_source_info_options[] = {
41435933ddSDimitry Andric // clang-format off
42*b5893f02SDimitry Andric { LLDB_OPT_SET_ALL, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCount, "The number of line entries to display." },
43*b5893f02SDimitry Andric { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "shlib", 's', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Look up the source in the given module or shared library (can be specified more than once)." },
44*b5893f02SDimitry Andric { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source." },
45*b5893f02SDimitry Andric { LLDB_OPT_SET_1, false, "line", 'l', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeLineNum, "The line number at which to start the displaying lines." },
46*b5893f02SDimitry Andric { LLDB_OPT_SET_1, false, "end-line", 'e', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeLineNum, "The line number at which to stop displaying lines." },
47*b5893f02SDimitry Andric { LLDB_OPT_SET_2, false, "name", 'n', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion, eArgTypeSymbol, "The name of a function whose source to display." },
48*b5893f02SDimitry Andric { LLDB_OPT_SET_3, false, "address", 'a', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeAddressOrExpression, "Lookup the address and display the source information for the corresponding file and line." },
49435933ddSDimitry Andric // clang-format on
50435933ddSDimitry Andric };
51435933ddSDimitry Andric
52435933ddSDimitry Andric class CommandObjectSourceInfo : public CommandObjectParsed {
53435933ddSDimitry Andric class CommandOptions : public Options {
54ac7ddfbfSEd Maste public:
CommandOptions()55435933ddSDimitry Andric CommandOptions() : Options() {}
56ac7ddfbfSEd Maste
574bb0738eSEd Maste ~CommandOptions() override = default;
58ac7ddfbfSEd Maste
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)595517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
60435933ddSDimitry Andric ExecutionContext *execution_context) override {
615517e702SDimitry Andric Status error;
62435933ddSDimitry Andric const int short_option = GetDefinitions()[option_idx].short_option;
63435933ddSDimitry Andric switch (short_option) {
64ac7ddfbfSEd Maste case 'l':
65435933ddSDimitry Andric if (option_arg.getAsInteger(0, start_line))
66435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid line number: '%s'",
67435933ddSDimitry Andric option_arg.str().c_str());
68ac7ddfbfSEd Maste break;
69ac7ddfbfSEd Maste
70a1bd240cSDimitry Andric case 'e':
71435933ddSDimitry Andric if (option_arg.getAsInteger(0, end_line))
72435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid line number: '%s'",
73435933ddSDimitry Andric option_arg.str().c_str());
74a1bd240cSDimitry Andric break;
75a1bd240cSDimitry Andric
76a1bd240cSDimitry Andric case 'c':
77435933ddSDimitry Andric if (option_arg.getAsInteger(0, num_lines))
78435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid line count: '%s'",
79435933ddSDimitry Andric option_arg.str().c_str());
80a1bd240cSDimitry Andric break;
81a1bd240cSDimitry Andric
82ac7ddfbfSEd Maste case 'f':
83ac7ddfbfSEd Maste file_name = option_arg;
84ac7ddfbfSEd Maste break;
85ac7ddfbfSEd Maste
86a1bd240cSDimitry Andric case 'n':
87a1bd240cSDimitry Andric symbol_name = option_arg;
88a1bd240cSDimitry Andric break;
89a1bd240cSDimitry Andric
90435933ddSDimitry Andric case 'a': {
914ba319b5SDimitry Andric address = OptionArgParser::ToAddress(execution_context, option_arg,
92435933ddSDimitry Andric LLDB_INVALID_ADDRESS, &error);
93435933ddSDimitry Andric } break;
94a1bd240cSDimitry Andric case 's':
95a1bd240cSDimitry Andric modules.push_back(std::string(option_arg));
96a1bd240cSDimitry Andric break;
97ac7ddfbfSEd Maste default:
98435933ddSDimitry Andric error.SetErrorStringWithFormat("unrecognized short option '%c'",
99435933ddSDimitry Andric short_option);
100ac7ddfbfSEd Maste break;
101ac7ddfbfSEd Maste }
102ac7ddfbfSEd Maste
103ac7ddfbfSEd Maste return error;
104ac7ddfbfSEd Maste }
105ac7ddfbfSEd Maste
OptionParsingStarting(ExecutionContext * execution_context)106435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
107ac7ddfbfSEd Maste file_spec.Clear();
108ac7ddfbfSEd Maste file_name.clear();
109a1bd240cSDimitry Andric symbol_name.clear();
110a1bd240cSDimitry Andric address = LLDB_INVALID_ADDRESS;
111ac7ddfbfSEd Maste start_line = 0;
112a1bd240cSDimitry Andric end_line = 0;
113a1bd240cSDimitry Andric num_lines = 0;
114a1bd240cSDimitry Andric modules.clear();
115ac7ddfbfSEd Maste }
116ac7ddfbfSEd Maste
GetDefinitions()117435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
118435933ddSDimitry Andric return llvm::makeArrayRef(g_source_info_options);
119ac7ddfbfSEd Maste }
1204bb0738eSEd Maste
121ac7ddfbfSEd Maste // Instance variables to hold the values for command options.
122ac7ddfbfSEd Maste FileSpec file_spec;
123ac7ddfbfSEd Maste std::string file_name;
124a1bd240cSDimitry Andric std::string symbol_name;
125a1bd240cSDimitry Andric lldb::addr_t address;
126ac7ddfbfSEd Maste uint32_t start_line;
127a1bd240cSDimitry Andric uint32_t end_line;
128a1bd240cSDimitry Andric uint32_t num_lines;
129a1bd240cSDimitry Andric STLStringArray modules;
130ac7ddfbfSEd Maste };
131ac7ddfbfSEd Maste
132ac7ddfbfSEd Maste public:
CommandObjectSourceInfo(CommandInterpreter & interpreter)133a1bd240cSDimitry Andric CommandObjectSourceInfo(CommandInterpreter &interpreter)
134435933ddSDimitry Andric : CommandObjectParsed(
135435933ddSDimitry Andric interpreter, "source info",
136435933ddSDimitry Andric "Display source line information for the current target "
1374bb0738eSEd Maste "process. Defaults to instruction pointer in current stack "
1384bb0738eSEd Maste "frame.",
1394bb0738eSEd Maste nullptr, eCommandRequiresTarget),
140435933ddSDimitry Andric m_options() {}
141ac7ddfbfSEd Maste
1424bb0738eSEd Maste ~CommandObjectSourceInfo() override = default;
143ac7ddfbfSEd Maste
GetOptions()144435933ddSDimitry Andric Options *GetOptions() override { return &m_options; }
145ac7ddfbfSEd Maste
146ac7ddfbfSEd Maste protected:
1474ba319b5SDimitry Andric // Dump the line entries in each symbol context. Return the number of entries
1484ba319b5SDimitry Andric // found. If module_list is set, only dump lines contained in one of the
1494ba319b5SDimitry Andric // modules. If file_spec is set, only dump lines in the file. If the
1504ba319b5SDimitry Andric // start_line option was specified, don't print lines less than start_line.
151435933ddSDimitry Andric // If the end_line option was specified, don't print lines greater than
1524ba319b5SDimitry Andric // end_line. If the num_lines option was specified, dont print more than
1534ba319b5SDimitry Andric // num_lines entries.
DumpLinesInSymbolContexts(Stream & strm,const SymbolContextList & sc_list,const ModuleList & module_list,const FileSpec & file_spec)154435933ddSDimitry Andric uint32_t DumpLinesInSymbolContexts(Stream &strm,
155435933ddSDimitry Andric const SymbolContextList &sc_list,
156435933ddSDimitry Andric const ModuleList &module_list,
157435933ddSDimitry Andric const FileSpec &file_spec) {
158a1bd240cSDimitry Andric uint32_t start_line = m_options.start_line;
159a1bd240cSDimitry Andric uint32_t end_line = m_options.end_line;
160a1bd240cSDimitry Andric uint32_t num_lines = m_options.num_lines;
161a1bd240cSDimitry Andric Target *target = m_exe_ctx.GetTargetPtr();
162a1bd240cSDimitry Andric
163a1bd240cSDimitry Andric uint32_t num_matches = 0;
164a1bd240cSDimitry Andric bool has_path = false;
165435933ddSDimitry Andric if (file_spec) {
166a1bd240cSDimitry Andric assert(file_spec.GetFilename().AsCString());
1674bb0738eSEd Maste has_path = (file_spec.GetDirectory().AsCString() != nullptr);
168a1bd240cSDimitry Andric }
169a1bd240cSDimitry Andric
170a1bd240cSDimitry Andric // Dump all the line entries for the file in the list.
171a1bd240cSDimitry Andric ConstString last_module_file_name;
172a1bd240cSDimitry Andric uint32_t num_scs = sc_list.GetSize();
173435933ddSDimitry Andric for (uint32_t i = 0; i < num_scs; ++i) {
174a1bd240cSDimitry Andric SymbolContext sc;
175a1bd240cSDimitry Andric sc_list.GetContextAtIndex(i, sc);
176435933ddSDimitry Andric if (sc.comp_unit) {
177a1bd240cSDimitry Andric Module *module = sc.module_sp.get();
178a1bd240cSDimitry Andric CompileUnit *cu = sc.comp_unit;
179a1bd240cSDimitry Andric const LineEntry &line_entry = sc.line_entry;
180a1bd240cSDimitry Andric assert(module && cu);
181a1bd240cSDimitry Andric
182a1bd240cSDimitry Andric // Are we looking for specific modules, files or lines?
183435933ddSDimitry Andric if (module_list.GetSize() &&
184435933ddSDimitry Andric module_list.GetIndexForModule(module) == LLDB_INVALID_INDEX32)
185a1bd240cSDimitry Andric continue;
186435933ddSDimitry Andric if (file_spec &&
187435933ddSDimitry Andric !lldb_private::FileSpec::Equal(file_spec, line_entry.file,
188435933ddSDimitry Andric has_path))
189a1bd240cSDimitry Andric continue;
190a1bd240cSDimitry Andric if (start_line > 0 && line_entry.line < start_line)
191a1bd240cSDimitry Andric continue;
192a1bd240cSDimitry Andric if (end_line > 0 && line_entry.line > end_line)
193a1bd240cSDimitry Andric continue;
194a1bd240cSDimitry Andric if (num_lines > 0 && num_matches > num_lines)
195a1bd240cSDimitry Andric continue;
196a1bd240cSDimitry Andric
197a1bd240cSDimitry Andric // Print a new header if the module changed.
198435933ddSDimitry Andric const ConstString &module_file_name =
199435933ddSDimitry Andric module->GetFileSpec().GetFilename();
200a1bd240cSDimitry Andric assert(module_file_name);
201435933ddSDimitry Andric if (module_file_name != last_module_file_name) {
202a1bd240cSDimitry Andric if (num_matches > 0)
203a1bd240cSDimitry Andric strm << "\n\n";
204a1bd240cSDimitry Andric strm << "Lines found in module `" << module_file_name << "\n";
205a1bd240cSDimitry Andric }
206a1bd240cSDimitry Andric // Dump the line entry.
207a1bd240cSDimitry Andric line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu,
208a1bd240cSDimitry Andric target, /*show_address_only=*/false);
209a1bd240cSDimitry Andric strm << "\n";
210a1bd240cSDimitry Andric last_module_file_name = module_file_name;
211a1bd240cSDimitry Andric num_matches++;
212a1bd240cSDimitry Andric }
213a1bd240cSDimitry Andric }
214a1bd240cSDimitry Andric return num_matches;
215a1bd240cSDimitry Andric }
216a1bd240cSDimitry Andric
217a1bd240cSDimitry Andric // Dump the requested line entries for the file in the compilation unit.
2184ba319b5SDimitry Andric // Return the number of entries found. If module_list is set, only dump lines
2194ba319b5SDimitry Andric // contained in one of the modules. If the start_line option was specified,
2204ba319b5SDimitry Andric // don't print lines less than start_line. If the end_line option was
2214ba319b5SDimitry Andric // specified, don't print lines greater than end_line. If the num_lines
2224ba319b5SDimitry Andric // option was specified, dont print more than num_lines entries.
DumpFileLinesInCompUnit(Stream & strm,Module * module,CompileUnit * cu,const FileSpec & file_spec)223435933ddSDimitry Andric uint32_t DumpFileLinesInCompUnit(Stream &strm, Module *module,
224435933ddSDimitry Andric CompileUnit *cu, const FileSpec &file_spec) {
225a1bd240cSDimitry Andric uint32_t start_line = m_options.start_line;
226a1bd240cSDimitry Andric uint32_t end_line = m_options.end_line;
227a1bd240cSDimitry Andric uint32_t num_lines = m_options.num_lines;
228a1bd240cSDimitry Andric Target *target = m_exe_ctx.GetTargetPtr();
229a1bd240cSDimitry Andric
230a1bd240cSDimitry Andric uint32_t num_matches = 0;
231a1bd240cSDimitry Andric assert(module);
232435933ddSDimitry Andric if (cu) {
233a1bd240cSDimitry Andric assert(file_spec.GetFilename().AsCString());
2344bb0738eSEd Maste bool has_path = (file_spec.GetDirectory().AsCString() != nullptr);
235a1bd240cSDimitry Andric const FileSpecList &cu_file_list = cu->GetSupportFiles();
236a1bd240cSDimitry Andric size_t file_idx = cu_file_list.FindFileIndex(0, file_spec, has_path);
237435933ddSDimitry Andric if (file_idx != UINT32_MAX) {
238a1bd240cSDimitry Andric // Update the file to how it appears in the CU.
239435933ddSDimitry Andric const FileSpec &cu_file_spec =
240435933ddSDimitry Andric cu_file_list.GetFileSpecAtIndex(file_idx);
241a1bd240cSDimitry Andric
242435933ddSDimitry Andric // Dump all matching lines at or above start_line for the file in the
243435933ddSDimitry Andric // CU.
244a1bd240cSDimitry Andric const ConstString &file_spec_name = file_spec.GetFilename();
245435933ddSDimitry Andric const ConstString &module_file_name =
246435933ddSDimitry Andric module->GetFileSpec().GetFilename();
247a1bd240cSDimitry Andric bool cu_header_printed = false;
248a1bd240cSDimitry Andric uint32_t line = start_line;
249435933ddSDimitry Andric while (true) {
250a1bd240cSDimitry Andric LineEntry line_entry;
251a1bd240cSDimitry Andric
2524ba319b5SDimitry Andric // Find the lowest index of a line entry with a line equal to or
2534ba319b5SDimitry Andric // higher than 'line'.
254a1bd240cSDimitry Andric uint32_t start_idx = 0;
255a1bd240cSDimitry Andric start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec,
256a1bd240cSDimitry Andric /*exact=*/false, &line_entry);
257a1bd240cSDimitry Andric if (start_idx == UINT32_MAX)
258a1bd240cSDimitry Andric // No more line entries for our file in this CU.
259a1bd240cSDimitry Andric break;
260a1bd240cSDimitry Andric
261a1bd240cSDimitry Andric if (end_line > 0 && line_entry.line > end_line)
262a1bd240cSDimitry Andric break;
263a1bd240cSDimitry Andric
2644ba319b5SDimitry Andric // Loop through to find any other entries for this line, dumping
2654ba319b5SDimitry Andric // each.
266a1bd240cSDimitry Andric line = line_entry.line;
267435933ddSDimitry Andric do {
268a1bd240cSDimitry Andric num_matches++;
269a1bd240cSDimitry Andric if (num_lines > 0 && num_matches > num_lines)
270a1bd240cSDimitry Andric break;
271435933ddSDimitry Andric assert(lldb_private::FileSpec::Equal(cu_file_spec, line_entry.file,
272435933ddSDimitry Andric has_path));
273435933ddSDimitry Andric if (!cu_header_printed) {
274a1bd240cSDimitry Andric if (num_matches > 0)
275a1bd240cSDimitry Andric strm << "\n\n";
276a1bd240cSDimitry Andric strm << "Lines found for file " << file_spec_name
277435933ddSDimitry Andric << " in compilation unit " << cu->GetFilename() << " in `"
278435933ddSDimitry Andric << module_file_name << "\n";
279a1bd240cSDimitry Andric cu_header_printed = true;
280a1bd240cSDimitry Andric }
281a1bd240cSDimitry Andric line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu,
282a1bd240cSDimitry Andric target, /*show_address_only=*/false);
283a1bd240cSDimitry Andric strm << "\n";
284a1bd240cSDimitry Andric
285a1bd240cSDimitry Andric // Anymore after this one?
286a1bd240cSDimitry Andric start_idx++;
287a1bd240cSDimitry Andric start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec,
288a1bd240cSDimitry Andric /*exact=*/true, &line_entry);
289a1bd240cSDimitry Andric } while (start_idx != UINT32_MAX);
290a1bd240cSDimitry Andric
291a1bd240cSDimitry Andric // Try the next higher line, starting over at start_idx 0.
292a1bd240cSDimitry Andric line++;
293a1bd240cSDimitry Andric }
294a1bd240cSDimitry Andric }
295a1bd240cSDimitry Andric }
296a1bd240cSDimitry Andric return num_matches;
297a1bd240cSDimitry Andric }
298a1bd240cSDimitry Andric
2994ba319b5SDimitry Andric // Dump the requested line entries for the file in the module. Return the
3004ba319b5SDimitry Andric // number of entries found. If module_list is set, only dump lines contained
3014ba319b5SDimitry Andric // in one of the modules. If the start_line option was specified, don't print
3024ba319b5SDimitry Andric // lines less than start_line. If the end_line option was specified, don't
3034ba319b5SDimitry Andric // print lines greater than end_line. If the num_lines option was specified,
3044ba319b5SDimitry Andric // dont print more than num_lines entries.
DumpFileLinesInModule(Stream & strm,Module * module,const FileSpec & file_spec)305435933ddSDimitry Andric uint32_t DumpFileLinesInModule(Stream &strm, Module *module,
306435933ddSDimitry Andric const FileSpec &file_spec) {
307a1bd240cSDimitry Andric uint32_t num_matches = 0;
308435933ddSDimitry Andric if (module) {
309435933ddSDimitry Andric // Look through all the compilation units (CUs) in this module for ones
3104ba319b5SDimitry Andric // that contain lines of code from this source file.
311435933ddSDimitry Andric for (size_t i = 0; i < module->GetNumCompileUnits(); i++) {
312a1bd240cSDimitry Andric // Look for a matching source file in this CU.
313a1bd240cSDimitry Andric CompUnitSP cu_sp(module->GetCompileUnitAtIndex(i));
314435933ddSDimitry Andric if (cu_sp) {
315435933ddSDimitry Andric num_matches +=
316435933ddSDimitry Andric DumpFileLinesInCompUnit(strm, module, cu_sp.get(), file_spec);
317a1bd240cSDimitry Andric }
318a1bd240cSDimitry Andric }
319a1bd240cSDimitry Andric }
320a1bd240cSDimitry Andric return num_matches;
321a1bd240cSDimitry Andric }
322a1bd240cSDimitry Andric
323435933ddSDimitry Andric // Given an address and a list of modules, append the symbol contexts of all
3244ba319b5SDimitry Andric // line entries containing the address found in the modules and return the
3254ba319b5SDimitry 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)326435933ddSDimitry Andric size_t GetSymbolContextsForAddress(const ModuleList &module_list,
327435933ddSDimitry Andric lldb::addr_t addr,
328435933ddSDimitry Andric SymbolContextList &sc_list,
329435933ddSDimitry Andric StreamString &error_strm) {
330a1bd240cSDimitry Andric Address so_addr;
331a1bd240cSDimitry Andric size_t num_matches = 0;
332a1bd240cSDimitry Andric assert(module_list.GetSize() > 0);
333a1bd240cSDimitry Andric Target *target = m_exe_ctx.GetTargetPtr();
334435933ddSDimitry Andric if (target->GetSectionLoadList().IsEmpty()) {
3354ba319b5SDimitry Andric // The target isn't loaded yet, we need to lookup the file address in all
3364ba319b5SDimitry Andric // modules. Note: the module list option does not apply to addresses.
337a1bd240cSDimitry Andric const size_t num_modules = module_list.GetSize();
338435933ddSDimitry Andric for (size_t i = 0; i < num_modules; ++i) {
339a1bd240cSDimitry Andric ModuleSP module_sp(module_list.GetModuleAtIndex(i));
340a1bd240cSDimitry Andric if (!module_sp)
341a1bd240cSDimitry Andric continue;
342435933ddSDimitry Andric if (module_sp->ResolveFileAddress(addr, so_addr)) {
343a1bd240cSDimitry Andric SymbolContext sc;
344a1bd240cSDimitry Andric sc.Clear(true);
345435933ddSDimitry Andric if (module_sp->ResolveSymbolContextForAddress(
346435933ddSDimitry Andric so_addr, eSymbolContextEverything, sc) &
347435933ddSDimitry Andric eSymbolContextLineEntry) {
348a1bd240cSDimitry Andric sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false);
349a1bd240cSDimitry Andric ++num_matches;
350a1bd240cSDimitry Andric }
351a1bd240cSDimitry Andric }
352a1bd240cSDimitry Andric }
353a1bd240cSDimitry Andric if (num_matches == 0)
354a1bd240cSDimitry Andric error_strm.Printf("Source information for file address 0x%" PRIx64
355435933ddSDimitry Andric " not found in any modules.\n",
356435933ddSDimitry Andric addr);
357435933ddSDimitry Andric } else {
3584ba319b5SDimitry Andric // The target has some things loaded, resolve this address to a compile
3594ba319b5SDimitry Andric // unit + file + line and display
360435933ddSDimitry Andric if (target->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) {
361a1bd240cSDimitry Andric ModuleSP module_sp(so_addr.GetModule());
362a1bd240cSDimitry Andric // Check to make sure this module is in our list.
363a1bd240cSDimitry Andric if (module_sp &&
364435933ddSDimitry Andric module_list.GetIndexForModule(module_sp.get()) !=
365435933ddSDimitry Andric LLDB_INVALID_INDEX32) {
366a1bd240cSDimitry Andric SymbolContext sc;
367a1bd240cSDimitry Andric sc.Clear(true);
368435933ddSDimitry Andric if (module_sp->ResolveSymbolContextForAddress(
369435933ddSDimitry Andric so_addr, eSymbolContextEverything, sc) &
370435933ddSDimitry Andric eSymbolContextLineEntry) {
371a1bd240cSDimitry Andric sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false);
372a1bd240cSDimitry Andric ++num_matches;
373435933ddSDimitry Andric } else {
374a1bd240cSDimitry Andric StreamString addr_strm;
375435933ddSDimitry Andric so_addr.Dump(&addr_strm, nullptr,
376435933ddSDimitry Andric Address::DumpStyleModuleWithFileAddress);
377435933ddSDimitry Andric error_strm.Printf(
378435933ddSDimitry Andric "Address 0x%" PRIx64 " resolves to %s, but there is"
379a1bd240cSDimitry Andric " no source information available for this address.\n",
380a1bd240cSDimitry Andric addr, addr_strm.GetData());
381a1bd240cSDimitry Andric }
382435933ddSDimitry Andric } else {
383a1bd240cSDimitry Andric StreamString addr_strm;
384435933ddSDimitry Andric so_addr.Dump(&addr_strm, nullptr,
385435933ddSDimitry Andric Address::DumpStyleModuleWithFileAddress);
386435933ddSDimitry Andric error_strm.Printf("Address 0x%" PRIx64
387435933ddSDimitry Andric " resolves to %s, but it cannot"
388a1bd240cSDimitry Andric " be found in any modules.\n",
389a1bd240cSDimitry Andric addr, addr_strm.GetData());
390a1bd240cSDimitry Andric }
391435933ddSDimitry Andric } else
392a1bd240cSDimitry Andric error_strm.Printf("Unable to resolve address 0x%" PRIx64 ".\n", addr);
393a1bd240cSDimitry Andric }
394a1bd240cSDimitry Andric return num_matches;
395a1bd240cSDimitry Andric }
396a1bd240cSDimitry Andric
3974ba319b5SDimitry Andric // Dump the line entries found in functions matching the name specified in
3984ba319b5SDimitry Andric // the option.
DumpLinesInFunctions(CommandReturnObject & result)399435933ddSDimitry Andric bool DumpLinesInFunctions(CommandReturnObject &result) {
400a1bd240cSDimitry Andric SymbolContextList sc_list_funcs;
401a1bd240cSDimitry Andric ConstString name(m_options.symbol_name.c_str());
402a1bd240cSDimitry Andric SymbolContextList sc_list_lines;
403a1bd240cSDimitry Andric Target *target = m_exe_ctx.GetTargetPtr();
404a1bd240cSDimitry Andric uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
405a1bd240cSDimitry Andric
406435933ddSDimitry Andric // Note: module_list can't be const& because FindFunctionSymbols isn't
407435933ddSDimitry Andric // const.
408435933ddSDimitry Andric ModuleList module_list =
409435933ddSDimitry Andric (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages();
410435933ddSDimitry Andric size_t num_matches =
411435933ddSDimitry Andric module_list.FindFunctions(name, eFunctionNameTypeAuto,
412a1bd240cSDimitry Andric /*include_symbols=*/false,
413a1bd240cSDimitry Andric /*include_inlines=*/true,
414435933ddSDimitry Andric /*append=*/true, sc_list_funcs);
415435933ddSDimitry Andric if (!num_matches) {
416a1bd240cSDimitry Andric // If we didn't find any functions with that name, try searching for
417a1bd240cSDimitry Andric // symbols that line up exactly with function addresses.
418a1bd240cSDimitry Andric SymbolContextList sc_list_symbols;
419435933ddSDimitry Andric size_t num_symbol_matches = module_list.FindFunctionSymbols(
420435933ddSDimitry Andric name, eFunctionNameTypeAuto, sc_list_symbols);
421435933ddSDimitry Andric for (size_t i = 0; i < num_symbol_matches; i++) {
422a1bd240cSDimitry Andric SymbolContext sc;
423a1bd240cSDimitry Andric sc_list_symbols.GetContextAtIndex(i, sc);
424435933ddSDimitry Andric if (sc.symbol && sc.symbol->ValueIsAddress()) {
425a1bd240cSDimitry Andric const Address &base_address = sc.symbol->GetAddressRef();
426a1bd240cSDimitry Andric Function *function = base_address.CalculateSymbolContextFunction();
427435933ddSDimitry Andric if (function) {
428a1bd240cSDimitry Andric sc_list_funcs.Append(SymbolContext(function));
429a1bd240cSDimitry Andric num_matches++;
430a1bd240cSDimitry Andric }
431a1bd240cSDimitry Andric }
432a1bd240cSDimitry Andric }
433a1bd240cSDimitry Andric }
434435933ddSDimitry Andric if (num_matches == 0) {
435a1bd240cSDimitry Andric result.AppendErrorWithFormat("Could not find function named \'%s\'.\n",
436a1bd240cSDimitry Andric m_options.symbol_name.c_str());
437a1bd240cSDimitry Andric return false;
438a1bd240cSDimitry Andric }
439435933ddSDimitry Andric for (size_t i = 0; i < num_matches; i++) {
440a1bd240cSDimitry Andric SymbolContext sc;
441a1bd240cSDimitry Andric sc_list_funcs.GetContextAtIndex(i, sc);
442a1bd240cSDimitry Andric bool context_found_for_symbol = false;
443a1bd240cSDimitry Andric // Loop through all the ranges in the function.
444a1bd240cSDimitry Andric AddressRange range;
445a1bd240cSDimitry Andric for (uint32_t r = 0;
446435933ddSDimitry Andric sc.GetAddressRange(eSymbolContextEverything, r,
447435933ddSDimitry Andric /*use_inline_block_range=*/true, range);
448435933ddSDimitry Andric ++r) {
449435933ddSDimitry Andric // Append the symbol contexts for each address in the range to
450435933ddSDimitry Andric // sc_list_lines.
451a1bd240cSDimitry Andric const Address &base_address = range.GetBaseAddress();
452a1bd240cSDimitry Andric const addr_t size = range.GetByteSize();
453a1bd240cSDimitry Andric lldb::addr_t start_addr = base_address.GetLoadAddress(target);
454a1bd240cSDimitry Andric if (start_addr == LLDB_INVALID_ADDRESS)
455a1bd240cSDimitry Andric start_addr = base_address.GetFileAddress();
456a1bd240cSDimitry Andric lldb::addr_t end_addr = start_addr + size;
457435933ddSDimitry Andric for (lldb::addr_t addr = start_addr; addr < end_addr;
458435933ddSDimitry Andric addr += addr_byte_size) {
459a1bd240cSDimitry Andric StreamString error_strm;
460435933ddSDimitry Andric if (!GetSymbolContextsForAddress(module_list, addr, sc_list_lines,
461435933ddSDimitry Andric error_strm))
462a1bd240cSDimitry Andric result.AppendWarningWithFormat("in symbol '%s': %s",
463a1bd240cSDimitry Andric sc.GetFunctionName().AsCString(),
464a1bd240cSDimitry Andric error_strm.GetData());
465a1bd240cSDimitry Andric else
466a1bd240cSDimitry Andric context_found_for_symbol = true;
467a1bd240cSDimitry Andric }
468a1bd240cSDimitry Andric }
469a1bd240cSDimitry Andric if (!context_found_for_symbol)
470a1bd240cSDimitry Andric result.AppendWarningWithFormat("Unable to find line information"
471a1bd240cSDimitry Andric " for matching symbol '%s'.\n",
472a1bd240cSDimitry Andric sc.GetFunctionName().AsCString());
473a1bd240cSDimitry Andric }
474435933ddSDimitry Andric if (sc_list_lines.GetSize() == 0) {
475a1bd240cSDimitry Andric result.AppendErrorWithFormat("No line information could be found"
476a1bd240cSDimitry Andric " for any symbols matching '%s'.\n",
477a1bd240cSDimitry Andric name.AsCString());
478a1bd240cSDimitry Andric return false;
479a1bd240cSDimitry Andric }
480a1bd240cSDimitry Andric FileSpec file_spec;
481435933ddSDimitry Andric if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list_lines,
482435933ddSDimitry Andric module_list, file_spec)) {
483435933ddSDimitry Andric result.AppendErrorWithFormat(
484435933ddSDimitry Andric "Unable to dump line information for symbol '%s'.\n",
485a1bd240cSDimitry Andric name.AsCString());
486a1bd240cSDimitry Andric return false;
487a1bd240cSDimitry Andric }
488a1bd240cSDimitry Andric return true;
489a1bd240cSDimitry Andric }
490a1bd240cSDimitry Andric
491a1bd240cSDimitry Andric // Dump the line entries found for the address specified in the option.
DumpLinesForAddress(CommandReturnObject & result)492435933ddSDimitry Andric bool DumpLinesForAddress(CommandReturnObject &result) {
493a1bd240cSDimitry Andric Target *target = m_exe_ctx.GetTargetPtr();
494a1bd240cSDimitry Andric SymbolContextList sc_list;
495a1bd240cSDimitry Andric
496a1bd240cSDimitry Andric StreamString error_strm;
497435933ddSDimitry Andric if (!GetSymbolContextsForAddress(target->GetImages(), m_options.address,
498435933ddSDimitry Andric sc_list, error_strm)) {
499a1bd240cSDimitry Andric result.AppendErrorWithFormat("%s.\n", error_strm.GetData());
500a1bd240cSDimitry Andric return false;
501a1bd240cSDimitry Andric }
502a1bd240cSDimitry Andric ModuleList module_list;
503a1bd240cSDimitry Andric FileSpec file_spec;
504435933ddSDimitry Andric if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list,
505435933ddSDimitry Andric module_list, file_spec)) {
506435933ddSDimitry Andric result.AppendErrorWithFormat("No modules contain load address 0x%" PRIx64
507435933ddSDimitry Andric ".\n",
508a1bd240cSDimitry Andric m_options.address);
509a1bd240cSDimitry Andric return false;
510a1bd240cSDimitry Andric }
511a1bd240cSDimitry Andric return true;
512a1bd240cSDimitry Andric }
513a1bd240cSDimitry Andric
514a1bd240cSDimitry Andric // Dump the line entries found in the file specified in the option.
DumpLinesForFile(CommandReturnObject & result)515435933ddSDimitry Andric bool DumpLinesForFile(CommandReturnObject &result) {
516*b5893f02SDimitry Andric FileSpec file_spec(m_options.file_name);
517a1bd240cSDimitry Andric const char *filename = m_options.file_name.c_str();
518a1bd240cSDimitry Andric Target *target = m_exe_ctx.GetTargetPtr();
519435933ddSDimitry Andric const ModuleList &module_list =
520435933ddSDimitry Andric (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages();
521a1bd240cSDimitry Andric
522a1bd240cSDimitry Andric bool displayed_something = false;
523a1bd240cSDimitry Andric const size_t num_modules = module_list.GetSize();
524435933ddSDimitry Andric for (uint32_t i = 0; i < num_modules; ++i) {
525a1bd240cSDimitry Andric // Dump lines for this module.
526a1bd240cSDimitry Andric Module *module = module_list.GetModulePointerAtIndex(i);
527a1bd240cSDimitry Andric assert(module);
528a1bd240cSDimitry Andric if (DumpFileLinesInModule(result.GetOutputStream(), module, file_spec))
529a1bd240cSDimitry Andric displayed_something = true;
530a1bd240cSDimitry Andric }
531435933ddSDimitry Andric if (!displayed_something) {
532435933ddSDimitry Andric result.AppendErrorWithFormat("No source filenames matched '%s'.\n",
533435933ddSDimitry Andric filename);
534a1bd240cSDimitry Andric return false;
535a1bd240cSDimitry Andric }
536a1bd240cSDimitry Andric return true;
537a1bd240cSDimitry Andric }
538a1bd240cSDimitry Andric
539a1bd240cSDimitry Andric // Dump the line entries for the current frame.
DumpLinesForFrame(CommandReturnObject & result)540435933ddSDimitry Andric bool DumpLinesForFrame(CommandReturnObject &result) {
541a1bd240cSDimitry Andric StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
542435933ddSDimitry Andric if (cur_frame == nullptr) {
543435933ddSDimitry Andric result.AppendError(
544435933ddSDimitry Andric "No selected frame to use to find the default source.");
545a1bd240cSDimitry Andric return false;
546435933ddSDimitry Andric } else if (!cur_frame->HasDebugInformation()) {
547a1bd240cSDimitry Andric result.AppendError("No debug info for the selected frame.");
548a1bd240cSDimitry Andric return false;
549435933ddSDimitry Andric } else {
550435933ddSDimitry Andric const SymbolContext &sc =
551435933ddSDimitry Andric cur_frame->GetSymbolContext(eSymbolContextLineEntry);
552a1bd240cSDimitry Andric SymbolContextList sc_list;
553a1bd240cSDimitry Andric sc_list.Append(sc);
554a1bd240cSDimitry Andric ModuleList module_list;
555a1bd240cSDimitry Andric FileSpec file_spec;
556435933ddSDimitry Andric if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list,
557435933ddSDimitry Andric module_list, file_spec)) {
558435933ddSDimitry Andric result.AppendError(
559435933ddSDimitry Andric "No source line info available for the selected frame.");
560a1bd240cSDimitry Andric return false;
561a1bd240cSDimitry Andric }
562a1bd240cSDimitry Andric }
563a1bd240cSDimitry Andric return true;
564a1bd240cSDimitry Andric }
565a1bd240cSDimitry Andric
DoExecute(Args & command,CommandReturnObject & result)566435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override {
567a1bd240cSDimitry Andric const size_t argc = command.GetArgumentCount();
568a1bd240cSDimitry Andric
569435933ddSDimitry Andric if (argc != 0) {
570a1bd240cSDimitry Andric result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n",
571435933ddSDimitry Andric GetCommandName().str().c_str());
572ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
573ac7ddfbfSEd Maste return false;
574ac7ddfbfSEd Maste }
575ac7ddfbfSEd Maste
576a1bd240cSDimitry Andric Target *target = m_exe_ctx.GetTargetPtr();
577435933ddSDimitry Andric if (target == nullptr) {
578a1bd240cSDimitry Andric target = m_interpreter.GetDebugger().GetSelectedTarget().get();
579435933ddSDimitry Andric if (target == nullptr) {
580a1bd240cSDimitry Andric result.AppendError("invalid target, create a debug target using the "
581a1bd240cSDimitry Andric "'target create' command.");
582a1bd240cSDimitry Andric result.SetStatus(eReturnStatusFailed);
583a1bd240cSDimitry Andric return false;
584a1bd240cSDimitry Andric }
585a1bd240cSDimitry Andric }
586a1bd240cSDimitry Andric
587a1bd240cSDimitry Andric uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
588a1bd240cSDimitry Andric result.GetOutputStream().SetAddressByteSize(addr_byte_size);
589a1bd240cSDimitry Andric result.GetErrorStream().SetAddressByteSize(addr_byte_size);
590a1bd240cSDimitry Andric
591a1bd240cSDimitry Andric // Collect the list of modules to search.
592a1bd240cSDimitry Andric m_module_list.Clear();
593435933ddSDimitry Andric if (!m_options.modules.empty()) {
594435933ddSDimitry Andric for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) {
595*b5893f02SDimitry Andric FileSpec module_file_spec(m_options.modules[i]);
596435933ddSDimitry Andric if (module_file_spec) {
597a1bd240cSDimitry Andric ModuleSpec module_spec(module_file_spec);
598a1bd240cSDimitry Andric if (target->GetImages().FindModules(module_spec, m_module_list) == 0)
599a1bd240cSDimitry Andric result.AppendWarningWithFormat("No module found for '%s'.\n",
600a1bd240cSDimitry Andric m_options.modules[i].c_str());
601a1bd240cSDimitry Andric }
602a1bd240cSDimitry Andric }
603435933ddSDimitry Andric if (!m_module_list.GetSize()) {
604a1bd240cSDimitry Andric result.AppendError("No modules match the input.");
605a1bd240cSDimitry Andric result.SetStatus(eReturnStatusFailed);
606a1bd240cSDimitry Andric return false;
607a1bd240cSDimitry Andric }
608435933ddSDimitry Andric } else if (target->GetImages().GetSize() == 0) {
609a1bd240cSDimitry Andric result.AppendError("The target has no associated executable images.");
610a1bd240cSDimitry Andric result.SetStatus(eReturnStatusFailed);
611a1bd240cSDimitry Andric return false;
612a1bd240cSDimitry Andric }
613a1bd240cSDimitry Andric
614a1bd240cSDimitry Andric // Check the arguments to see what lines we should dump.
615435933ddSDimitry Andric if (!m_options.symbol_name.empty()) {
616a1bd240cSDimitry Andric // Print lines for symbol.
617a1bd240cSDimitry Andric if (DumpLinesInFunctions(result))
618a1bd240cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
619a1bd240cSDimitry Andric else
620a1bd240cSDimitry Andric result.SetStatus(eReturnStatusFailed);
621435933ddSDimitry Andric } else if (m_options.address != LLDB_INVALID_ADDRESS) {
622a1bd240cSDimitry Andric // Print lines for an address.
623a1bd240cSDimitry Andric if (DumpLinesForAddress(result))
624a1bd240cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
625a1bd240cSDimitry Andric else
626a1bd240cSDimitry Andric result.SetStatus(eReturnStatusFailed);
627435933ddSDimitry Andric } else if (!m_options.file_name.empty()) {
628a1bd240cSDimitry Andric // Dump lines for a file.
629a1bd240cSDimitry Andric if (DumpLinesForFile(result))
630a1bd240cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
631a1bd240cSDimitry Andric else
632a1bd240cSDimitry Andric result.SetStatus(eReturnStatusFailed);
633435933ddSDimitry Andric } else {
634a1bd240cSDimitry Andric // Dump the line for the current frame.
635a1bd240cSDimitry Andric if (DumpLinesForFrame(result))
636a1bd240cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
637a1bd240cSDimitry Andric else
638a1bd240cSDimitry Andric result.SetStatus(eReturnStatusFailed);
639a1bd240cSDimitry Andric }
640a1bd240cSDimitry Andric return result.Succeeded();
641a1bd240cSDimitry Andric }
642a1bd240cSDimitry Andric
643ac7ddfbfSEd Maste CommandOptions m_options;
644a1bd240cSDimitry Andric ModuleList m_module_list;
645ac7ddfbfSEd Maste };
646ac7ddfbfSEd Maste
647ac7ddfbfSEd Maste #pragma mark CommandObjectSourceList
648ac7ddfbfSEd Maste //-------------------------------------------------------------------------
649ac7ddfbfSEd Maste // CommandObjectSourceList
650ac7ddfbfSEd Maste //-------------------------------------------------------------------------
651ac7ddfbfSEd Maste
652*b5893f02SDimitry Andric static constexpr OptionDefinition g_source_list_options[] = {
653435933ddSDimitry Andric // clang-format off
654*b5893f02SDimitry Andric { LLDB_OPT_SET_ALL, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCount, "The number of source lines to display." },
655*b5893f02SDimitry Andric { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "shlib", 's', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Look up the source file in the given shared library." },
656*b5893f02SDimitry Andric { LLDB_OPT_SET_ALL, false, "show-breakpoints", 'b', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Show the line table locations from the debug information that indicate valid places to set source level breakpoints." },
657*b5893f02SDimitry Andric { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source." },
658*b5893f02SDimitry Andric { LLDB_OPT_SET_1, false, "line", 'l', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeLineNum, "The line number at which to start the display source." },
659*b5893f02SDimitry Andric { LLDB_OPT_SET_2, false, "name", 'n', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion, eArgTypeSymbol, "The name of a function whose source to display." },
660*b5893f02SDimitry Andric { LLDB_OPT_SET_3, false, "address", 'a', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeAddressOrExpression, "Lookup the address and display the source information for the corresponding file and line." },
661*b5893f02SDimitry Andric { LLDB_OPT_SET_4, false, "reverse", 'r', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Reverse the listing to look backwards from the last displayed block of source." },
662435933ddSDimitry Andric // clang-format on
663435933ddSDimitry Andric };
664435933ddSDimitry Andric
665435933ddSDimitry Andric class CommandObjectSourceList : public CommandObjectParsed {
666435933ddSDimitry Andric class CommandOptions : public Options {
667ac7ddfbfSEd Maste public:
CommandOptions()668435933ddSDimitry Andric CommandOptions() : Options() {}
669ac7ddfbfSEd Maste
6704bb0738eSEd Maste ~CommandOptions() override = default;
671ac7ddfbfSEd Maste
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)6725517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
673435933ddSDimitry Andric ExecutionContext *execution_context) override {
6745517e702SDimitry Andric Status error;
675435933ddSDimitry Andric const int short_option = GetDefinitions()[option_idx].short_option;
676435933ddSDimitry Andric switch (short_option) {
677ac7ddfbfSEd Maste case 'l':
678435933ddSDimitry Andric if (option_arg.getAsInteger(0, start_line))
679435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid line number: '%s'",
680435933ddSDimitry Andric option_arg.str().c_str());
681ac7ddfbfSEd Maste break;
682ac7ddfbfSEd Maste
683ac7ddfbfSEd Maste case 'c':
684435933ddSDimitry Andric if (option_arg.getAsInteger(0, num_lines))
685435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid line count: '%s'",
686435933ddSDimitry Andric option_arg.str().c_str());
687ac7ddfbfSEd Maste break;
688ac7ddfbfSEd Maste
689ac7ddfbfSEd Maste case 'f':
690ac7ddfbfSEd Maste file_name = option_arg;
691ac7ddfbfSEd Maste break;
692ac7ddfbfSEd Maste
693ac7ddfbfSEd Maste case 'n':
694ac7ddfbfSEd Maste symbol_name = option_arg;
695ac7ddfbfSEd Maste break;
696ac7ddfbfSEd Maste
697435933ddSDimitry Andric case 'a': {
6984ba319b5SDimitry Andric address = OptionArgParser::ToAddress(execution_context, option_arg,
699435933ddSDimitry Andric LLDB_INVALID_ADDRESS, &error);
700435933ddSDimitry Andric } break;
701ac7ddfbfSEd Maste case 's':
702ac7ddfbfSEd Maste modules.push_back(std::string(option_arg));
703ac7ddfbfSEd Maste break;
704ac7ddfbfSEd Maste
705ac7ddfbfSEd Maste case 'b':
706ac7ddfbfSEd Maste show_bp_locs = true;
707ac7ddfbfSEd Maste break;
708ac7ddfbfSEd Maste case 'r':
709ac7ddfbfSEd Maste reverse = true;
710ac7ddfbfSEd Maste break;
711ac7ddfbfSEd Maste default:
712435933ddSDimitry Andric error.SetErrorStringWithFormat("unrecognized short option '%c'",
713435933ddSDimitry Andric short_option);
714ac7ddfbfSEd Maste break;
715ac7ddfbfSEd Maste }
716ac7ddfbfSEd Maste
717ac7ddfbfSEd Maste return error;
718ac7ddfbfSEd Maste }
719ac7ddfbfSEd Maste
OptionParsingStarting(ExecutionContext * execution_context)720435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
721ac7ddfbfSEd Maste file_spec.Clear();
722ac7ddfbfSEd Maste file_name.clear();
723ac7ddfbfSEd Maste symbol_name.clear();
724ac7ddfbfSEd Maste address = LLDB_INVALID_ADDRESS;
725ac7ddfbfSEd Maste start_line = 0;
726ac7ddfbfSEd Maste num_lines = 0;
727ac7ddfbfSEd Maste show_bp_locs = false;
728ac7ddfbfSEd Maste reverse = false;
729ac7ddfbfSEd Maste modules.clear();
730ac7ddfbfSEd Maste }
731ac7ddfbfSEd Maste
GetDefinitions()732435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
733435933ddSDimitry Andric return llvm::makeArrayRef(g_source_list_options);
734ac7ddfbfSEd Maste }
7354bb0738eSEd Maste
736ac7ddfbfSEd Maste // Instance variables to hold the values for command options.
737ac7ddfbfSEd Maste FileSpec file_spec;
738ac7ddfbfSEd Maste std::string file_name;
739ac7ddfbfSEd Maste std::string symbol_name;
740ac7ddfbfSEd Maste lldb::addr_t address;
741ac7ddfbfSEd Maste uint32_t start_line;
742ac7ddfbfSEd Maste uint32_t num_lines;
743ac7ddfbfSEd Maste STLStringArray modules;
744ac7ddfbfSEd Maste bool show_bp_locs;
745ac7ddfbfSEd Maste bool reverse;
746ac7ddfbfSEd Maste };
747ac7ddfbfSEd Maste
748ac7ddfbfSEd Maste public:
CommandObjectSourceList(CommandInterpreter & interpreter)7494bb0738eSEd Maste CommandObjectSourceList(CommandInterpreter &interpreter)
7504bb0738eSEd Maste : CommandObjectParsed(interpreter, "source list",
751435933ddSDimitry Andric "Display source code for the current target "
752435933ddSDimitry Andric "process as specified by options.",
753435933ddSDimitry Andric nullptr, eCommandRequiresTarget),
754435933ddSDimitry Andric m_options() {}
755ac7ddfbfSEd Maste
7564bb0738eSEd Maste ~CommandObjectSourceList() override = default;
757ac7ddfbfSEd Maste
GetOptions()758435933ddSDimitry Andric Options *GetOptions() override { return &m_options; }
759ac7ddfbfSEd Maste
GetRepeatCommand(Args & current_command_args,uint32_t index)760435933ddSDimitry Andric const char *GetRepeatCommand(Args ¤t_command_args,
761435933ddSDimitry Andric uint32_t index) override {
7624ba319b5SDimitry Andric // This is kind of gross, but the command hasn't been parsed yet so we
7634ba319b5SDimitry Andric // can't look at the option values for this invocation... I have to scan
7644ba319b5SDimitry Andric // the arguments directly.
765435933ddSDimitry Andric auto iter =
766435933ddSDimitry Andric llvm::find_if(current_command_args, [](const Args::ArgEntry &e) {
767435933ddSDimitry Andric return e.ref == "-r" || e.ref == "--reverse";
768435933ddSDimitry Andric });
769435933ddSDimitry Andric if (iter == current_command_args.end())
770435933ddSDimitry Andric return m_cmd_name.c_str();
771435933ddSDimitry Andric
772435933ddSDimitry Andric if (m_reverse_name.empty()) {
773ac7ddfbfSEd Maste m_reverse_name = m_cmd_name;
774ac7ddfbfSEd Maste m_reverse_name.append(" -r");
775ac7ddfbfSEd Maste }
776ac7ddfbfSEd Maste return m_reverse_name.c_str();
777ac7ddfbfSEd Maste }
778ac7ddfbfSEd Maste
779ac7ddfbfSEd Maste protected:
780435933ddSDimitry Andric struct SourceInfo {
781ac7ddfbfSEd Maste ConstString function;
782ac7ddfbfSEd Maste LineEntry line_entry;
783ac7ddfbfSEd Maste
SourceInfoCommandObjectSourceList::SourceInfo784435933ddSDimitry Andric SourceInfo(const ConstString &name, const LineEntry &line_entry)
785435933ddSDimitry Andric : function(name), line_entry(line_entry) {}
786ac7ddfbfSEd Maste
SourceInfoCommandObjectSourceList::SourceInfo787435933ddSDimitry Andric SourceInfo() : function(), line_entry() {}
788ac7ddfbfSEd Maste
IsValidCommandObjectSourceList::SourceInfo789435933ddSDimitry Andric bool IsValid() const { return (bool)function && line_entry.IsValid(); }
790ac7ddfbfSEd Maste
operator ==CommandObjectSourceList::SourceInfo791435933ddSDimitry Andric bool operator==(const SourceInfo &rhs) const {
792ac7ddfbfSEd Maste return function == rhs.function &&
7934bb0738eSEd Maste line_entry.original_file == rhs.line_entry.original_file &&
794ac7ddfbfSEd Maste line_entry.line == rhs.line_entry.line;
795ac7ddfbfSEd Maste }
796ac7ddfbfSEd Maste
operator !=CommandObjectSourceList::SourceInfo797435933ddSDimitry Andric bool operator!=(const SourceInfo &rhs) const {
798ac7ddfbfSEd Maste return function != rhs.function ||
7994bb0738eSEd Maste line_entry.original_file != rhs.line_entry.original_file ||
800ac7ddfbfSEd Maste line_entry.line != rhs.line_entry.line;
801ac7ddfbfSEd Maste }
802ac7ddfbfSEd Maste
operator <CommandObjectSourceList::SourceInfo803435933ddSDimitry Andric bool operator<(const SourceInfo &rhs) const {
804ac7ddfbfSEd Maste if (function.GetCString() < rhs.function.GetCString())
805ac7ddfbfSEd Maste return true;
806435933ddSDimitry Andric if (line_entry.file.GetDirectory().GetCString() <
807435933ddSDimitry Andric rhs.line_entry.file.GetDirectory().GetCString())
808ac7ddfbfSEd Maste return true;
809435933ddSDimitry Andric if (line_entry.file.GetFilename().GetCString() <
810435933ddSDimitry Andric rhs.line_entry.file.GetFilename().GetCString())
811ac7ddfbfSEd Maste return true;
812ac7ddfbfSEd Maste if (line_entry.line < rhs.line_entry.line)
813ac7ddfbfSEd Maste return true;
814ac7ddfbfSEd Maste return false;
815ac7ddfbfSEd Maste }
816ac7ddfbfSEd Maste };
817ac7ddfbfSEd Maste
DisplayFunctionSource(const SymbolContext & sc,SourceInfo & source_info,CommandReturnObject & result)818435933ddSDimitry Andric size_t DisplayFunctionSource(const SymbolContext &sc, SourceInfo &source_info,
819435933ddSDimitry Andric CommandReturnObject &result) {
820435933ddSDimitry Andric if (!source_info.IsValid()) {
821ac7ddfbfSEd Maste source_info.function = sc.GetFunctionName();
822ac7ddfbfSEd Maste source_info.line_entry = sc.GetFunctionStartLineEntry();
823ac7ddfbfSEd Maste }
824ac7ddfbfSEd Maste
825435933ddSDimitry Andric if (sc.function) {
826ac7ddfbfSEd Maste Target *target = m_exe_ctx.GetTargetPtr();
827ac7ddfbfSEd Maste
828ac7ddfbfSEd Maste FileSpec start_file;
829ac7ddfbfSEd Maste uint32_t start_line;
830ac7ddfbfSEd Maste uint32_t end_line;
831ac7ddfbfSEd Maste FileSpec end_file;
832ac7ddfbfSEd Maste
833435933ddSDimitry Andric if (sc.block == nullptr) {
834ac7ddfbfSEd Maste // Not an inlined function
835ac7ddfbfSEd Maste sc.function->GetStartLineSourceInfo(start_file, start_line);
836435933ddSDimitry Andric if (start_line == 0) {
837435933ddSDimitry Andric result.AppendErrorWithFormat("Could not find line information for "
838435933ddSDimitry Andric "start of function: \"%s\".\n",
839435933ddSDimitry Andric source_info.function.GetCString());
840ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
841ac7ddfbfSEd Maste return 0;
842ac7ddfbfSEd Maste }
843ac7ddfbfSEd Maste sc.function->GetEndLineSourceInfo(end_file, end_line);
844435933ddSDimitry Andric } else {
845ac7ddfbfSEd Maste // We have an inlined function
846ac7ddfbfSEd Maste start_file = source_info.line_entry.file;
847ac7ddfbfSEd Maste start_line = source_info.line_entry.line;
848ac7ddfbfSEd Maste end_line = start_line + m_options.num_lines;
849ac7ddfbfSEd Maste }
850ac7ddfbfSEd Maste
851435933ddSDimitry Andric // This is a little hacky, but the first line table entry for a function
8524ba319b5SDimitry Andric // points to the "{" that starts the function block. It would be nice to
8534ba319b5SDimitry Andric // actually get the function declaration in there too. So back up a bit,
8544ba319b5SDimitry Andric // but not further than what you're going to display.
855ac7ddfbfSEd Maste uint32_t extra_lines;
856ac7ddfbfSEd Maste if (m_options.num_lines >= 10)
857ac7ddfbfSEd Maste extra_lines = 5;
858ac7ddfbfSEd Maste else
859ac7ddfbfSEd Maste extra_lines = m_options.num_lines / 2;
860ac7ddfbfSEd Maste uint32_t line_no;
861ac7ddfbfSEd Maste if (start_line <= extra_lines)
862ac7ddfbfSEd Maste line_no = 1;
863ac7ddfbfSEd Maste else
864ac7ddfbfSEd Maste line_no = start_line - extra_lines;
865ac7ddfbfSEd Maste
866435933ddSDimitry Andric // For fun, if the function is shorter than the number of lines we're
8674ba319b5SDimitry Andric // supposed to display, only display the function...
868435933ddSDimitry Andric if (end_line != 0) {
869ac7ddfbfSEd Maste if (m_options.num_lines > end_line - line_no)
870ac7ddfbfSEd Maste m_options.num_lines = end_line - line_no + extra_lines;
871ac7ddfbfSEd Maste }
872ac7ddfbfSEd Maste
873ac7ddfbfSEd Maste m_breakpoint_locations.Clear();
874ac7ddfbfSEd Maste
875435933ddSDimitry Andric if (m_options.show_bp_locs) {
876ac7ddfbfSEd Maste const bool show_inlines = true;
877ac7ddfbfSEd Maste m_breakpoint_locations.Reset(start_file, 0, show_inlines);
878435933ddSDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter(
879435933ddSDimitry Andric m_exe_ctx.GetTargetSP());
880ac7ddfbfSEd Maste target_search_filter.Search(m_breakpoint_locations);
881ac7ddfbfSEd Maste }
882ac7ddfbfSEd Maste
883435933ddSDimitry Andric result.AppendMessageWithFormat("File: %s\n",
884435933ddSDimitry Andric start_file.GetPath().c_str());
885435933ddSDimitry Andric // We don't care about the column here.
886435933ddSDimitry Andric const uint32_t column = 0;
887435933ddSDimitry Andric return target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
888acac075bSDimitry Andric start_file, line_no, column, 0, m_options.num_lines, "",
889435933ddSDimitry Andric &result.GetOutputStream(), GetBreakpointLocations());
890435933ddSDimitry Andric } else {
891435933ddSDimitry Andric result.AppendErrorWithFormat(
892435933ddSDimitry Andric "Could not find function info for: \"%s\".\n",
893435933ddSDimitry Andric m_options.symbol_name.c_str());
894ac7ddfbfSEd Maste }
895ac7ddfbfSEd Maste return 0;
896ac7ddfbfSEd Maste }
897ac7ddfbfSEd Maste
8984ba319b5SDimitry Andric // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols
8994ba319b5SDimitry Andric // functions "take a possibly empty vector of strings which are names of
9004ba319b5SDimitry Andric // modules, and run the two search functions on the subset of the full module
9014ba319b5SDimitry Andric // list that matches the strings in the input vector". If we wanted to put
9024ba319b5SDimitry Andric // these somewhere, there should probably be a module-filter-list that can be
9034ba319b5SDimitry Andric // passed to the various ModuleList::Find* calls, which would either be a
9044ba319b5SDimitry Andric // vector of string names or a ModuleSpecList.
FindMatchingFunctions(Target * target,const ConstString & name,SymbolContextList & sc_list)905435933ddSDimitry Andric size_t FindMatchingFunctions(Target *target, const ConstString &name,
906435933ddSDimitry Andric SymbolContextList &sc_list) {
907ac7ddfbfSEd Maste // Displaying the source for a symbol:
908ac7ddfbfSEd Maste bool include_inlines = true;
909ac7ddfbfSEd Maste bool append = true;
910ac7ddfbfSEd Maste bool include_symbols = false;
911ac7ddfbfSEd Maste size_t num_matches = 0;
912ac7ddfbfSEd Maste
913ac7ddfbfSEd Maste if (m_options.num_lines == 0)
914ac7ddfbfSEd Maste m_options.num_lines = 10;
915ac7ddfbfSEd Maste
916ac7ddfbfSEd Maste const size_t num_modules = m_options.modules.size();
917435933ddSDimitry Andric if (num_modules > 0) {
918ac7ddfbfSEd Maste ModuleList matching_modules;
919435933ddSDimitry Andric for (size_t i = 0; i < num_modules; ++i) {
920*b5893f02SDimitry Andric FileSpec module_file_spec(m_options.modules[i]);
921435933ddSDimitry Andric if (module_file_spec) {
922ac7ddfbfSEd Maste ModuleSpec module_spec(module_file_spec);
923ac7ddfbfSEd Maste matching_modules.Clear();
924ac7ddfbfSEd Maste target->GetImages().FindModules(module_spec, matching_modules);
925435933ddSDimitry Andric num_matches += matching_modules.FindFunctions(
926435933ddSDimitry Andric name, eFunctionNameTypeAuto, include_symbols, include_inlines,
927435933ddSDimitry Andric append, sc_list);
928ac7ddfbfSEd Maste }
929ac7ddfbfSEd Maste }
930435933ddSDimitry Andric } else {
931435933ddSDimitry Andric num_matches = target->GetImages().FindFunctions(
932435933ddSDimitry Andric name, eFunctionNameTypeAuto, include_symbols, include_inlines, append,
933435933ddSDimitry Andric sc_list);
934ac7ddfbfSEd Maste }
935ac7ddfbfSEd Maste return num_matches;
936ac7ddfbfSEd Maste }
937ac7ddfbfSEd Maste
FindMatchingFunctionSymbols(Target * target,const ConstString & name,SymbolContextList & sc_list)938435933ddSDimitry Andric size_t FindMatchingFunctionSymbols(Target *target, const ConstString &name,
939435933ddSDimitry Andric SymbolContextList &sc_list) {
940ac7ddfbfSEd Maste size_t num_matches = 0;
941ac7ddfbfSEd Maste const size_t num_modules = m_options.modules.size();
942435933ddSDimitry Andric if (num_modules > 0) {
943ac7ddfbfSEd Maste ModuleList matching_modules;
944435933ddSDimitry Andric for (size_t i = 0; i < num_modules; ++i) {
945*b5893f02SDimitry Andric FileSpec module_file_spec(m_options.modules[i]);
946435933ddSDimitry Andric if (module_file_spec) {
947ac7ddfbfSEd Maste ModuleSpec module_spec(module_file_spec);
948ac7ddfbfSEd Maste matching_modules.Clear();
949ac7ddfbfSEd Maste target->GetImages().FindModules(module_spec, matching_modules);
950435933ddSDimitry Andric num_matches += matching_modules.FindFunctionSymbols(
951435933ddSDimitry Andric name, eFunctionNameTypeAuto, sc_list);
952ac7ddfbfSEd Maste }
953ac7ddfbfSEd Maste }
954435933ddSDimitry Andric } else {
955435933ddSDimitry Andric num_matches = target->GetImages().FindFunctionSymbols(
956435933ddSDimitry Andric name, eFunctionNameTypeAuto, sc_list);
957ac7ddfbfSEd Maste }
958ac7ddfbfSEd Maste return num_matches;
959ac7ddfbfSEd Maste }
960ac7ddfbfSEd Maste
DoExecute(Args & command,CommandReturnObject & result)961435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override {
962ac7ddfbfSEd Maste const size_t argc = command.GetArgumentCount();
963ac7ddfbfSEd Maste
964435933ddSDimitry Andric if (argc != 0) {
965435933ddSDimitry Andric result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n",
966435933ddSDimitry Andric GetCommandName().str().c_str());
967ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
968ac7ddfbfSEd Maste return false;
969ac7ddfbfSEd Maste }
970ac7ddfbfSEd Maste
971ac7ddfbfSEd Maste Target *target = m_exe_ctx.GetTargetPtr();
972ac7ddfbfSEd Maste
973435933ddSDimitry Andric if (!m_options.symbol_name.empty()) {
974ac7ddfbfSEd Maste SymbolContextList sc_list;
975ac7ddfbfSEd Maste ConstString name(m_options.symbol_name.c_str());
976ac7ddfbfSEd Maste
977ac7ddfbfSEd Maste // Displaying the source for a symbol. Search for function named name.
978ac7ddfbfSEd Maste size_t num_matches = FindMatchingFunctions(target, name, sc_list);
979435933ddSDimitry Andric if (!num_matches) {
980435933ddSDimitry Andric // If we didn't find any functions with that name, try searching for
9814ba319b5SDimitry Andric // symbols that line up exactly with function addresses.
982ac7ddfbfSEd Maste SymbolContextList sc_list_symbols;
983435933ddSDimitry Andric size_t num_symbol_matches =
984435933ddSDimitry Andric FindMatchingFunctionSymbols(target, name, sc_list_symbols);
985435933ddSDimitry Andric for (size_t i = 0; i < num_symbol_matches; i++) {
986ac7ddfbfSEd Maste SymbolContext sc;
987ac7ddfbfSEd Maste sc_list_symbols.GetContextAtIndex(i, sc);
988435933ddSDimitry Andric if (sc.symbol && sc.symbol->ValueIsAddress()) {
9891c3bbb01SEd Maste const Address &base_address = sc.symbol->GetAddressRef();
990ac7ddfbfSEd Maste Function *function = base_address.CalculateSymbolContextFunction();
991435933ddSDimitry Andric if (function) {
992ac7ddfbfSEd Maste sc_list.Append(SymbolContext(function));
993ac7ddfbfSEd Maste num_matches++;
994ac7ddfbfSEd Maste break;
995ac7ddfbfSEd Maste }
996ac7ddfbfSEd Maste }
997ac7ddfbfSEd Maste }
998ac7ddfbfSEd Maste }
999ac7ddfbfSEd Maste
1000435933ddSDimitry Andric if (num_matches == 0) {
1001435933ddSDimitry Andric result.AppendErrorWithFormat("Could not find function named: \"%s\".\n",
1002435933ddSDimitry Andric m_options.symbol_name.c_str());
1003ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
1004ac7ddfbfSEd Maste return false;
1005ac7ddfbfSEd Maste }
1006ac7ddfbfSEd Maste
1007435933ddSDimitry Andric if (num_matches > 1) {
1008ac7ddfbfSEd Maste std::set<SourceInfo> source_match_set;
1009ac7ddfbfSEd Maste
1010ac7ddfbfSEd Maste bool displayed_something = false;
1011435933ddSDimitry Andric for (size_t i = 0; i < num_matches; i++) {
1012ac7ddfbfSEd Maste SymbolContext sc;
1013ac7ddfbfSEd Maste sc_list.GetContextAtIndex(i, sc);
1014ac7ddfbfSEd Maste SourceInfo source_info(sc.GetFunctionName(),
1015ac7ddfbfSEd Maste sc.GetFunctionStartLineEntry());
1016ac7ddfbfSEd Maste
1017435933ddSDimitry Andric if (source_info.IsValid()) {
1018435933ddSDimitry Andric if (source_match_set.find(source_info) == source_match_set.end()) {
1019ac7ddfbfSEd Maste source_match_set.insert(source_info);
1020ac7ddfbfSEd Maste if (DisplayFunctionSource(sc, source_info, result))
1021ac7ddfbfSEd Maste displayed_something = true;
1022ac7ddfbfSEd Maste }
1023ac7ddfbfSEd Maste }
1024ac7ddfbfSEd Maste }
1025ac7ddfbfSEd Maste
1026ac7ddfbfSEd Maste if (displayed_something)
1027ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult);
1028ac7ddfbfSEd Maste else
1029ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
1030435933ddSDimitry Andric } else {
1031ac7ddfbfSEd Maste SymbolContext sc;
1032ac7ddfbfSEd Maste sc_list.GetContextAtIndex(0, sc);
1033ac7ddfbfSEd Maste SourceInfo source_info;
1034ac7ddfbfSEd Maste
1035435933ddSDimitry Andric if (DisplayFunctionSource(sc, source_info, result)) {
1036ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult);
1037435933ddSDimitry Andric } else {
1038ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
1039ac7ddfbfSEd Maste }
1040ac7ddfbfSEd Maste }
1041ac7ddfbfSEd Maste return result.Succeeded();
1042435933ddSDimitry Andric } else if (m_options.address != LLDB_INVALID_ADDRESS) {
1043ac7ddfbfSEd Maste Address so_addr;
1044ac7ddfbfSEd Maste StreamString error_strm;
1045ac7ddfbfSEd Maste SymbolContextList sc_list;
1046ac7ddfbfSEd Maste
1047435933ddSDimitry Andric if (target->GetSectionLoadList().IsEmpty()) {
10484ba319b5SDimitry Andric // The target isn't loaded yet, we need to lookup the file address in
10494ba319b5SDimitry Andric // all modules
1050ac7ddfbfSEd Maste const ModuleList &module_list = target->GetImages();
1051ac7ddfbfSEd Maste const size_t num_modules = module_list.GetSize();
1052435933ddSDimitry Andric for (size_t i = 0; i < num_modules; ++i) {
1053ac7ddfbfSEd Maste ModuleSP module_sp(module_list.GetModuleAtIndex(i));
1054435933ddSDimitry Andric if (module_sp &&
1055435933ddSDimitry Andric module_sp->ResolveFileAddress(m_options.address, so_addr)) {
1056ac7ddfbfSEd Maste SymbolContext sc;
1057ac7ddfbfSEd Maste sc.Clear(true);
1058435933ddSDimitry Andric if (module_sp->ResolveSymbolContextForAddress(
1059435933ddSDimitry Andric so_addr, eSymbolContextEverything, sc) &
1060435933ddSDimitry Andric eSymbolContextLineEntry)
1061ac7ddfbfSEd Maste sc_list.Append(sc);
1062ac7ddfbfSEd Maste }
1063ac7ddfbfSEd Maste }
1064ac7ddfbfSEd Maste
1065435933ddSDimitry Andric if (sc_list.GetSize() == 0) {
1066435933ddSDimitry Andric result.AppendErrorWithFormat(
1067435933ddSDimitry Andric "no modules have source information for file address 0x%" PRIx64
1068435933ddSDimitry Andric ".\n",
1069ac7ddfbfSEd Maste m_options.address);
1070ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
1071ac7ddfbfSEd Maste return false;
1072ac7ddfbfSEd Maste }
1073435933ddSDimitry Andric } else {
10744ba319b5SDimitry Andric // The target has some things loaded, resolve this address to a compile
10754ba319b5SDimitry Andric // unit + file + line and display
1076435933ddSDimitry Andric if (target->GetSectionLoadList().ResolveLoadAddress(m_options.address,
1077435933ddSDimitry Andric so_addr)) {
1078ac7ddfbfSEd Maste ModuleSP module_sp(so_addr.GetModule());
1079435933ddSDimitry Andric if (module_sp) {
1080ac7ddfbfSEd Maste SymbolContext sc;
1081ac7ddfbfSEd Maste sc.Clear(true);
1082435933ddSDimitry Andric if (module_sp->ResolveSymbolContextForAddress(
1083435933ddSDimitry Andric so_addr, eSymbolContextEverything, sc) &
1084435933ddSDimitry Andric eSymbolContextLineEntry) {
1085ac7ddfbfSEd Maste sc_list.Append(sc);
1086435933ddSDimitry Andric } else {
1087435933ddSDimitry Andric so_addr.Dump(&error_strm, nullptr,
1088435933ddSDimitry Andric Address::DumpStyleModuleWithFileAddress);
1089435933ddSDimitry Andric result.AppendErrorWithFormat("address resolves to %s, but there "
1090435933ddSDimitry Andric "is no line table information "
1091435933ddSDimitry Andric "available for this address.\n",
1092ac7ddfbfSEd Maste error_strm.GetData());
1093ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
1094ac7ddfbfSEd Maste return false;
1095ac7ddfbfSEd Maste }
1096ac7ddfbfSEd Maste }
1097ac7ddfbfSEd Maste }
1098ac7ddfbfSEd Maste
1099435933ddSDimitry Andric if (sc_list.GetSize() == 0) {
1100435933ddSDimitry Andric result.AppendErrorWithFormat(
1101435933ddSDimitry Andric "no modules contain load address 0x%" PRIx64 ".\n",
1102435933ddSDimitry Andric m_options.address);
1103ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
1104ac7ddfbfSEd Maste return false;
1105ac7ddfbfSEd Maste }
1106ac7ddfbfSEd Maste }
1107ac7ddfbfSEd Maste uint32_t num_matches = sc_list.GetSize();
1108435933ddSDimitry Andric for (uint32_t i = 0; i < num_matches; ++i) {
1109ac7ddfbfSEd Maste SymbolContext sc;
1110ac7ddfbfSEd Maste sc_list.GetContextAtIndex(i, sc);
1111435933ddSDimitry Andric if (sc.comp_unit) {
1112435933ddSDimitry Andric if (m_options.show_bp_locs) {
1113ac7ddfbfSEd Maste m_breakpoint_locations.Clear();
1114ac7ddfbfSEd Maste const bool show_inlines = true;
1115ac7ddfbfSEd Maste m_breakpoint_locations.Reset(*sc.comp_unit, 0, show_inlines);
1116435933ddSDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter(
1117435933ddSDimitry Andric target->shared_from_this());
1118ac7ddfbfSEd Maste target_search_filter.Search(m_breakpoint_locations);
1119ac7ddfbfSEd Maste }
1120ac7ddfbfSEd Maste
1121ac7ddfbfSEd Maste bool show_fullpaths = true;
1122ac7ddfbfSEd Maste bool show_module = true;
1123ac7ddfbfSEd Maste bool show_inlined_frames = true;
11247aa51b79SEd Maste const bool show_function_arguments = true;
11251c3bbb01SEd Maste const bool show_function_name = true;
1126ac7ddfbfSEd Maste sc.DumpStopContext(&result.GetOutputStream(),
1127ac7ddfbfSEd Maste m_exe_ctx.GetBestExecutionContextScope(),
1128ac7ddfbfSEd Maste sc.line_entry.range.GetBaseAddress(),
1129435933ddSDimitry Andric show_fullpaths, show_module, show_inlined_frames,
1130435933ddSDimitry Andric show_function_arguments, show_function_name);
1131ac7ddfbfSEd Maste result.GetOutputStream().EOL();
1132ac7ddfbfSEd Maste
1133ac7ddfbfSEd Maste if (m_options.num_lines == 0)
1134ac7ddfbfSEd Maste m_options.num_lines = 10;
1135ac7ddfbfSEd Maste
1136435933ddSDimitry Andric size_t lines_to_back_up =
1137435933ddSDimitry Andric m_options.num_lines >= 10 ? 5 : m_options.num_lines / 2;
1138ac7ddfbfSEd Maste
1139435933ddSDimitry Andric const uint32_t column =
1140435933ddSDimitry Andric (m_interpreter.GetDebugger().GetStopShowColumn() !=
1141435933ddSDimitry Andric eStopShowColumnNone)
1142435933ddSDimitry Andric ? sc.line_entry.column
1143435933ddSDimitry Andric : 0;
1144435933ddSDimitry Andric target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
1145acac075bSDimitry Andric sc.comp_unit, sc.line_entry.line, column, lines_to_back_up,
1146435933ddSDimitry Andric m_options.num_lines - lines_to_back_up, "->",
1147435933ddSDimitry Andric &result.GetOutputStream(), GetBreakpointLocations());
1148ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult);
1149ac7ddfbfSEd Maste }
1150ac7ddfbfSEd Maste }
1151435933ddSDimitry Andric } else if (m_options.file_name.empty()) {
11524ba319b5SDimitry Andric // Last valid source manager context, or the current frame if no valid
11534ba319b5SDimitry Andric // last context in source manager. One little trick here, if you type the
11544ba319b5SDimitry Andric // exact same list command twice in a row, it is more likely because you
11554ba319b5SDimitry Andric // typed it once, then typed it again
1156435933ddSDimitry Andric if (m_options.start_line == 0) {
1157435933ddSDimitry Andric if (target->GetSourceManager().DisplayMoreWithLineNumbers(
1158435933ddSDimitry Andric &result.GetOutputStream(), m_options.num_lines,
1159435933ddSDimitry Andric m_options.reverse, GetBreakpointLocations())) {
1160ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult);
1161ac7ddfbfSEd Maste }
1162435933ddSDimitry Andric } else {
1163ac7ddfbfSEd Maste if (m_options.num_lines == 0)
1164ac7ddfbfSEd Maste m_options.num_lines = 10;
1165ac7ddfbfSEd Maste
1166435933ddSDimitry Andric if (m_options.show_bp_locs) {
1167435933ddSDimitry Andric SourceManager::FileSP last_file_sp(
1168435933ddSDimitry Andric target->GetSourceManager().GetLastFile());
1169435933ddSDimitry Andric if (last_file_sp) {
1170ac7ddfbfSEd Maste const bool show_inlines = true;
1171435933ddSDimitry Andric m_breakpoint_locations.Reset(last_file_sp->GetFileSpec(), 0,
1172435933ddSDimitry Andric show_inlines);
1173435933ddSDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter(
1174435933ddSDimitry Andric target->shared_from_this());
1175ac7ddfbfSEd Maste target_search_filter.Search(m_breakpoint_locations);
1176ac7ddfbfSEd Maste }
1177435933ddSDimitry Andric } else
1178ac7ddfbfSEd Maste m_breakpoint_locations.Clear();
1179ac7ddfbfSEd Maste
1180435933ddSDimitry Andric const uint32_t column = 0;
1181435933ddSDimitry Andric if (target->GetSourceManager()
1182435933ddSDimitry Andric .DisplaySourceLinesWithLineNumbersUsingLastFile(
1183ac7ddfbfSEd Maste m_options.start_line, // Line to display
1184ac7ddfbfSEd Maste m_options.num_lines, // Lines after line to
1185ac7ddfbfSEd Maste UINT32_MAX, // Don't mark "line"
1186435933ddSDimitry Andric column,
1187ac7ddfbfSEd Maste "", // Don't mark "line"
1188435933ddSDimitry Andric &result.GetOutputStream(), GetBreakpointLocations())) {
1189ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult);
1190ac7ddfbfSEd Maste }
1191ac7ddfbfSEd Maste }
1192435933ddSDimitry Andric } else {
1193ac7ddfbfSEd Maste const char *filename = m_options.file_name.c_str();
1194ac7ddfbfSEd Maste
1195ac7ddfbfSEd Maste bool check_inlines = false;
1196ac7ddfbfSEd Maste SymbolContextList sc_list;
1197ac7ddfbfSEd Maste size_t num_matches = 0;
1198ac7ddfbfSEd Maste
1199435933ddSDimitry Andric if (!m_options.modules.empty()) {
1200ac7ddfbfSEd Maste ModuleList matching_modules;
1201435933ddSDimitry Andric for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) {
1202*b5893f02SDimitry Andric FileSpec module_file_spec(m_options.modules[i]);
1203435933ddSDimitry Andric if (module_file_spec) {
1204ac7ddfbfSEd Maste ModuleSpec module_spec(module_file_spec);
1205ac7ddfbfSEd Maste matching_modules.Clear();
1206ac7ddfbfSEd Maste target->GetImages().FindModules(module_spec, matching_modules);
1207435933ddSDimitry Andric num_matches += matching_modules.ResolveSymbolContextForFilePath(
1208435933ddSDimitry Andric filename, 0, check_inlines,
1209*b5893f02SDimitry Andric SymbolContextItem(eSymbolContextModule |
1210*b5893f02SDimitry Andric eSymbolContextCompUnit),
1211*b5893f02SDimitry Andric sc_list);
1212ac7ddfbfSEd Maste }
1213ac7ddfbfSEd Maste }
1214435933ddSDimitry Andric } else {
1215435933ddSDimitry Andric num_matches = target->GetImages().ResolveSymbolContextForFilePath(
1216435933ddSDimitry Andric filename, 0, check_inlines,
1217435933ddSDimitry Andric eSymbolContextModule | eSymbolContextCompUnit, sc_list);
1218ac7ddfbfSEd Maste }
1219ac7ddfbfSEd Maste
1220435933ddSDimitry Andric if (num_matches == 0) {
1221ac7ddfbfSEd Maste result.AppendErrorWithFormat("Could not find source file \"%s\".\n",
1222ac7ddfbfSEd Maste m_options.file_name.c_str());
1223ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
1224ac7ddfbfSEd Maste return false;
1225ac7ddfbfSEd Maste }
1226ac7ddfbfSEd Maste
1227435933ddSDimitry Andric if (num_matches > 1) {
1228ac7ddfbfSEd Maste bool got_multiple = false;
12294bb0738eSEd Maste FileSpec *test_cu_spec = nullptr;
1230ac7ddfbfSEd Maste
1231435933ddSDimitry Andric for (unsigned i = 0; i < num_matches; i++) {
1232ac7ddfbfSEd Maste SymbolContext sc;
1233ac7ddfbfSEd Maste sc_list.GetContextAtIndex(i, sc);
1234435933ddSDimitry Andric if (sc.comp_unit) {
1235435933ddSDimitry Andric if (test_cu_spec) {
1236ac7ddfbfSEd Maste if (test_cu_spec != static_cast<FileSpec *>(sc.comp_unit))
1237ac7ddfbfSEd Maste got_multiple = true;
1238ac7ddfbfSEd Maste break;
1239435933ddSDimitry Andric } else
1240ac7ddfbfSEd Maste test_cu_spec = sc.comp_unit;
1241ac7ddfbfSEd Maste }
1242ac7ddfbfSEd Maste }
1243435933ddSDimitry Andric if (got_multiple) {
1244435933ddSDimitry Andric result.AppendErrorWithFormat(
1245435933ddSDimitry Andric "Multiple source files found matching: \"%s.\"\n",
1246ac7ddfbfSEd Maste m_options.file_name.c_str());
1247ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
1248ac7ddfbfSEd Maste return false;
1249ac7ddfbfSEd Maste }
1250ac7ddfbfSEd Maste }
1251ac7ddfbfSEd Maste
1252ac7ddfbfSEd Maste SymbolContext sc;
1253435933ddSDimitry Andric if (sc_list.GetContextAtIndex(0, sc)) {
1254435933ddSDimitry Andric if (sc.comp_unit) {
1255435933ddSDimitry Andric if (m_options.show_bp_locs) {
1256ac7ddfbfSEd Maste const bool show_inlines = true;
1257ac7ddfbfSEd Maste m_breakpoint_locations.Reset(*sc.comp_unit, 0, show_inlines);
1258435933ddSDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter(
1259435933ddSDimitry Andric target->shared_from_this());
1260ac7ddfbfSEd Maste target_search_filter.Search(m_breakpoint_locations);
1261435933ddSDimitry Andric } else
1262ac7ddfbfSEd Maste m_breakpoint_locations.Clear();
1263ac7ddfbfSEd Maste
1264ac7ddfbfSEd Maste if (m_options.num_lines == 0)
1265ac7ddfbfSEd Maste m_options.num_lines = 10;
1266435933ddSDimitry Andric const uint32_t column = 0;
1267435933ddSDimitry Andric target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
1268acac075bSDimitry Andric sc.comp_unit, m_options.start_line, column,
1269acac075bSDimitry Andric 0, m_options.num_lines,
1270acac075bSDimitry Andric "", &result.GetOutputStream(), GetBreakpointLocations());
1271ac7ddfbfSEd Maste
1272ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult);
1273435933ddSDimitry Andric } else {
1274ac7ddfbfSEd Maste result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n",
1275ac7ddfbfSEd Maste m_options.file_name.c_str());
1276ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
1277ac7ddfbfSEd Maste return false;
1278ac7ddfbfSEd Maste }
1279ac7ddfbfSEd Maste }
1280ac7ddfbfSEd Maste }
1281ac7ddfbfSEd Maste return result.Succeeded();
1282ac7ddfbfSEd Maste }
1283ac7ddfbfSEd Maste
GetBreakpointLocations()1284435933ddSDimitry Andric const SymbolContextList *GetBreakpointLocations() {
1285ac7ddfbfSEd Maste if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0)
1286ac7ddfbfSEd Maste return &m_breakpoint_locations.GetFileLineMatches();
12874bb0738eSEd Maste return nullptr;
1288ac7ddfbfSEd Maste }
12894bb0738eSEd Maste
1290ac7ddfbfSEd Maste CommandOptions m_options;
1291ac7ddfbfSEd Maste FileLineResolver m_breakpoint_locations;
1292ac7ddfbfSEd Maste std::string m_reverse_name;
1293ac7ddfbfSEd Maste };
1294ac7ddfbfSEd Maste
1295ac7ddfbfSEd Maste #pragma mark CommandObjectMultiwordSource
1296ac7ddfbfSEd Maste //-------------------------------------------------------------------------
1297ac7ddfbfSEd Maste // CommandObjectMultiwordSource
1298ac7ddfbfSEd Maste //-------------------------------------------------------------------------
1299ac7ddfbfSEd Maste
CommandObjectMultiwordSource(CommandInterpreter & interpreter)1300435933ddSDimitry Andric CommandObjectMultiwordSource::CommandObjectMultiwordSource(
1301435933ddSDimitry Andric CommandInterpreter &interpreter)
1302435933ddSDimitry Andric : CommandObjectMultiword(interpreter, "source", "Commands for examining "
1303435933ddSDimitry Andric "source code described by "
1304435933ddSDimitry Andric "debug information for the "
1305435933ddSDimitry Andric "current target process.",
1306435933ddSDimitry Andric "source <subcommand> [<subcommand-options>]") {
1307435933ddSDimitry Andric LoadSubCommand("info",
1308435933ddSDimitry Andric CommandObjectSP(new CommandObjectSourceInfo(interpreter)));
1309435933ddSDimitry Andric LoadSubCommand("list",
1310435933ddSDimitry Andric CommandObjectSP(new CommandObjectSourceList(interpreter)));
1311ac7ddfbfSEd Maste }
1312ac7ddfbfSEd Maste
13134bb0738eSEd Maste CommandObjectMultiwordSource::~CommandObjectMultiwordSource() = default;
1314