1dda28197Spatrick //===-- CommandObjectSource.cpp -------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "CommandObjectSource.h"
10061da546Spatrick
11061da546Spatrick #include "lldb/Core/Debugger.h"
12061da546Spatrick #include "lldb/Core/FileLineResolver.h"
13061da546Spatrick #include "lldb/Core/Module.h"
14061da546Spatrick #include "lldb/Core/ModuleSpec.h"
15061da546Spatrick #include "lldb/Core/SourceManager.h"
16061da546Spatrick #include "lldb/Host/OptionParser.h"
17*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
18061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
19061da546Spatrick #include "lldb/Interpreter/OptionArgParser.h"
20be691f3bSpatrick #include "lldb/Interpreter/OptionValueFileColonLine.h"
21061da546Spatrick #include "lldb/Interpreter/Options.h"
22061da546Spatrick #include "lldb/Symbol/CompileUnit.h"
23061da546Spatrick #include "lldb/Symbol/Function.h"
24061da546Spatrick #include "lldb/Symbol/Symbol.h"
25061da546Spatrick #include "lldb/Target/SectionLoadList.h"
26061da546Spatrick #include "lldb/Target/StackFrame.h"
27061da546Spatrick #include "lldb/Utility/FileSpec.h"
28*f6aab3d8Srobert #include <optional>
29061da546Spatrick
30061da546Spatrick using namespace lldb;
31061da546Spatrick using namespace lldb_private;
32061da546Spatrick
33061da546Spatrick #pragma mark CommandObjectSourceInfo
34061da546Spatrick // CommandObjectSourceInfo - debug line entries dumping command
35061da546Spatrick #define LLDB_OPTIONS_source_info
36061da546Spatrick #include "CommandOptions.inc"
37061da546Spatrick
38061da546Spatrick class CommandObjectSourceInfo : public CommandObjectParsed {
39061da546Spatrick class CommandOptions : public Options {
40061da546Spatrick public:
41*f6aab3d8Srobert CommandOptions() = default;
42061da546Spatrick
43061da546Spatrick ~CommandOptions() override = default;
44061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)45061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
46061da546Spatrick ExecutionContext *execution_context) override {
47061da546Spatrick Status error;
48061da546Spatrick const int short_option = GetDefinitions()[option_idx].short_option;
49061da546Spatrick switch (short_option) {
50061da546Spatrick case 'l':
51061da546Spatrick if (option_arg.getAsInteger(0, start_line))
52061da546Spatrick error.SetErrorStringWithFormat("invalid line number: '%s'",
53061da546Spatrick option_arg.str().c_str());
54061da546Spatrick break;
55061da546Spatrick
56061da546Spatrick case 'e':
57061da546Spatrick if (option_arg.getAsInteger(0, end_line))
58061da546Spatrick error.SetErrorStringWithFormat("invalid line number: '%s'",
59061da546Spatrick option_arg.str().c_str());
60061da546Spatrick break;
61061da546Spatrick
62061da546Spatrick case 'c':
63061da546Spatrick if (option_arg.getAsInteger(0, num_lines))
64061da546Spatrick error.SetErrorStringWithFormat("invalid line count: '%s'",
65061da546Spatrick option_arg.str().c_str());
66061da546Spatrick break;
67061da546Spatrick
68061da546Spatrick case 'f':
69dda28197Spatrick file_name = std::string(option_arg);
70061da546Spatrick break;
71061da546Spatrick
72061da546Spatrick case 'n':
73dda28197Spatrick symbol_name = std::string(option_arg);
74061da546Spatrick break;
75061da546Spatrick
76061da546Spatrick case 'a': {
77061da546Spatrick address = OptionArgParser::ToAddress(execution_context, option_arg,
78061da546Spatrick LLDB_INVALID_ADDRESS, &error);
79061da546Spatrick } break;
80061da546Spatrick case 's':
81061da546Spatrick modules.push_back(std::string(option_arg));
82061da546Spatrick break;
83061da546Spatrick default:
84061da546Spatrick llvm_unreachable("Unimplemented option");
85061da546Spatrick }
86061da546Spatrick
87061da546Spatrick return error;
88061da546Spatrick }
89061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)90061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
91061da546Spatrick file_spec.Clear();
92061da546Spatrick file_name.clear();
93061da546Spatrick symbol_name.clear();
94061da546Spatrick address = LLDB_INVALID_ADDRESS;
95061da546Spatrick start_line = 0;
96061da546Spatrick end_line = 0;
97061da546Spatrick num_lines = 0;
98061da546Spatrick modules.clear();
99061da546Spatrick }
100061da546Spatrick
GetDefinitions()101061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
102*f6aab3d8Srobert return llvm::ArrayRef(g_source_info_options);
103061da546Spatrick }
104061da546Spatrick
105061da546Spatrick // Instance variables to hold the values for command options.
106061da546Spatrick FileSpec file_spec;
107061da546Spatrick std::string file_name;
108061da546Spatrick std::string symbol_name;
109061da546Spatrick lldb::addr_t address;
110061da546Spatrick uint32_t start_line;
111061da546Spatrick uint32_t end_line;
112061da546Spatrick uint32_t num_lines;
113061da546Spatrick std::vector<std::string> modules;
114061da546Spatrick };
115061da546Spatrick
116061da546Spatrick public:
CommandObjectSourceInfo(CommandInterpreter & interpreter)117061da546Spatrick CommandObjectSourceInfo(CommandInterpreter &interpreter)
118061da546Spatrick : CommandObjectParsed(
119061da546Spatrick interpreter, "source info",
120061da546Spatrick "Display source line information for the current target "
121061da546Spatrick "process. Defaults to instruction pointer in current stack "
122061da546Spatrick "frame.",
123*f6aab3d8Srobert nullptr, eCommandRequiresTarget) {}
124061da546Spatrick
125061da546Spatrick ~CommandObjectSourceInfo() override = default;
126061da546Spatrick
GetOptions()127061da546Spatrick Options *GetOptions() override { return &m_options; }
128061da546Spatrick
129061da546Spatrick protected:
130061da546Spatrick // Dump the line entries in each symbol context. Return the number of entries
131061da546Spatrick // found. If module_list is set, only dump lines contained in one of the
132061da546Spatrick // modules. If file_spec is set, only dump lines in the file. If the
133061da546Spatrick // start_line option was specified, don't print lines less than start_line.
134061da546Spatrick // If the end_line option was specified, don't print lines greater than
135061da546Spatrick // end_line. If the num_lines option was specified, dont print more than
136061da546Spatrick // num_lines entries.
DumpLinesInSymbolContexts(Stream & strm,const SymbolContextList & sc_list,const ModuleList & module_list,const FileSpec & file_spec)137061da546Spatrick uint32_t DumpLinesInSymbolContexts(Stream &strm,
138061da546Spatrick const SymbolContextList &sc_list,
139061da546Spatrick const ModuleList &module_list,
140061da546Spatrick const FileSpec &file_spec) {
141061da546Spatrick uint32_t start_line = m_options.start_line;
142061da546Spatrick uint32_t end_line = m_options.end_line;
143061da546Spatrick uint32_t num_lines = m_options.num_lines;
144061da546Spatrick Target *target = m_exe_ctx.GetTargetPtr();
145061da546Spatrick
146061da546Spatrick uint32_t num_matches = 0;
147061da546Spatrick // Dump all the line entries for the file in the list.
148061da546Spatrick ConstString last_module_file_name;
149061da546Spatrick uint32_t num_scs = sc_list.GetSize();
150061da546Spatrick for (uint32_t i = 0; i < num_scs; ++i) {
151061da546Spatrick SymbolContext sc;
152061da546Spatrick sc_list.GetContextAtIndex(i, sc);
153061da546Spatrick if (sc.comp_unit) {
154061da546Spatrick Module *module = sc.module_sp.get();
155061da546Spatrick CompileUnit *cu = sc.comp_unit;
156061da546Spatrick const LineEntry &line_entry = sc.line_entry;
157061da546Spatrick assert(module && cu);
158061da546Spatrick
159061da546Spatrick // Are we looking for specific modules, files or lines?
160061da546Spatrick if (module_list.GetSize() &&
161061da546Spatrick module_list.GetIndexForModule(module) == LLDB_INVALID_INDEX32)
162061da546Spatrick continue;
163061da546Spatrick if (!FileSpec::Match(file_spec, line_entry.file))
164061da546Spatrick continue;
165061da546Spatrick if (start_line > 0 && line_entry.line < start_line)
166061da546Spatrick continue;
167061da546Spatrick if (end_line > 0 && line_entry.line > end_line)
168061da546Spatrick continue;
169061da546Spatrick if (num_lines > 0 && num_matches > num_lines)
170061da546Spatrick continue;
171061da546Spatrick
172061da546Spatrick // Print a new header if the module changed.
173061da546Spatrick ConstString module_file_name = module->GetFileSpec().GetFilename();
174061da546Spatrick assert(module_file_name);
175061da546Spatrick if (module_file_name != last_module_file_name) {
176061da546Spatrick if (num_matches > 0)
177061da546Spatrick strm << "\n\n";
178061da546Spatrick strm << "Lines found in module `" << module_file_name << "\n";
179061da546Spatrick }
180061da546Spatrick // Dump the line entry.
181061da546Spatrick line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu,
182061da546Spatrick target, /*show_address_only=*/false);
183061da546Spatrick strm << "\n";
184061da546Spatrick last_module_file_name = module_file_name;
185061da546Spatrick num_matches++;
186061da546Spatrick }
187061da546Spatrick }
188061da546Spatrick return num_matches;
189061da546Spatrick }
190061da546Spatrick
191061da546Spatrick // Dump the requested line entries for the file in the compilation unit.
192061da546Spatrick // Return the number of entries found. If module_list is set, only dump lines
193061da546Spatrick // contained in one of the modules. If the start_line option was specified,
194061da546Spatrick // don't print lines less than start_line. If the end_line option was
195061da546Spatrick // specified, don't print lines greater than end_line. If the num_lines
196061da546Spatrick // option was specified, dont print more than num_lines entries.
DumpFileLinesInCompUnit(Stream & strm,Module * module,CompileUnit * cu,const FileSpec & file_spec)197061da546Spatrick uint32_t DumpFileLinesInCompUnit(Stream &strm, Module *module,
198061da546Spatrick CompileUnit *cu, const FileSpec &file_spec) {
199061da546Spatrick uint32_t start_line = m_options.start_line;
200061da546Spatrick uint32_t end_line = m_options.end_line;
201061da546Spatrick uint32_t num_lines = m_options.num_lines;
202061da546Spatrick Target *target = m_exe_ctx.GetTargetPtr();
203061da546Spatrick
204061da546Spatrick uint32_t num_matches = 0;
205061da546Spatrick assert(module);
206061da546Spatrick if (cu) {
207061da546Spatrick assert(file_spec.GetFilename().AsCString());
208061da546Spatrick bool has_path = (file_spec.GetDirectory().AsCString() != nullptr);
209061da546Spatrick const FileSpecList &cu_file_list = cu->GetSupportFiles();
210061da546Spatrick size_t file_idx = cu_file_list.FindFileIndex(0, file_spec, has_path);
211061da546Spatrick if (file_idx != UINT32_MAX) {
212061da546Spatrick // Update the file to how it appears in the CU.
213061da546Spatrick const FileSpec &cu_file_spec =
214061da546Spatrick cu_file_list.GetFileSpecAtIndex(file_idx);
215061da546Spatrick
216061da546Spatrick // Dump all matching lines at or above start_line for the file in the
217061da546Spatrick // CU.
218061da546Spatrick ConstString file_spec_name = file_spec.GetFilename();
219061da546Spatrick ConstString module_file_name = module->GetFileSpec().GetFilename();
220061da546Spatrick bool cu_header_printed = false;
221061da546Spatrick uint32_t line = start_line;
222061da546Spatrick while (true) {
223061da546Spatrick LineEntry line_entry;
224061da546Spatrick
225061da546Spatrick // Find the lowest index of a line entry with a line equal to or
226061da546Spatrick // higher than 'line'.
227061da546Spatrick uint32_t start_idx = 0;
228061da546Spatrick start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec,
229061da546Spatrick /*exact=*/false, &line_entry);
230061da546Spatrick if (start_idx == UINT32_MAX)
231061da546Spatrick // No more line entries for our file in this CU.
232061da546Spatrick break;
233061da546Spatrick
234061da546Spatrick if (end_line > 0 && line_entry.line > end_line)
235061da546Spatrick break;
236061da546Spatrick
237061da546Spatrick // Loop through to find any other entries for this line, dumping
238061da546Spatrick // each.
239061da546Spatrick line = line_entry.line;
240061da546Spatrick do {
241061da546Spatrick num_matches++;
242061da546Spatrick if (num_lines > 0 && num_matches > num_lines)
243061da546Spatrick break;
244061da546Spatrick assert(cu_file_spec == line_entry.file);
245061da546Spatrick if (!cu_header_printed) {
246061da546Spatrick if (num_matches > 0)
247061da546Spatrick strm << "\n\n";
248061da546Spatrick strm << "Lines found for file " << file_spec_name
249061da546Spatrick << " in compilation unit "
250061da546Spatrick << cu->GetPrimaryFile().GetFilename() << " in `"
251061da546Spatrick << module_file_name << "\n";
252061da546Spatrick cu_header_printed = true;
253061da546Spatrick }
254061da546Spatrick line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu,
255061da546Spatrick target, /*show_address_only=*/false);
256061da546Spatrick strm << "\n";
257061da546Spatrick
258061da546Spatrick // Anymore after this one?
259061da546Spatrick start_idx++;
260061da546Spatrick start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec,
261061da546Spatrick /*exact=*/true, &line_entry);
262061da546Spatrick } while (start_idx != UINT32_MAX);
263061da546Spatrick
264061da546Spatrick // Try the next higher line, starting over at start_idx 0.
265061da546Spatrick line++;
266061da546Spatrick }
267061da546Spatrick }
268061da546Spatrick }
269061da546Spatrick return num_matches;
270061da546Spatrick }
271061da546Spatrick
272061da546Spatrick // Dump the requested line entries for the file in the module. Return the
273061da546Spatrick // number of entries found. If module_list is set, only dump lines contained
274061da546Spatrick // in one of the modules. If the start_line option was specified, don't print
275061da546Spatrick // lines less than start_line. If the end_line option was specified, don't
276061da546Spatrick // print lines greater than end_line. If the num_lines option was specified,
277061da546Spatrick // dont print more than num_lines entries.
DumpFileLinesInModule(Stream & strm,Module * module,const FileSpec & file_spec)278061da546Spatrick uint32_t DumpFileLinesInModule(Stream &strm, Module *module,
279061da546Spatrick const FileSpec &file_spec) {
280061da546Spatrick uint32_t num_matches = 0;
281061da546Spatrick if (module) {
282061da546Spatrick // Look through all the compilation units (CUs) in this module for ones
283061da546Spatrick // that contain lines of code from this source file.
284061da546Spatrick for (size_t i = 0; i < module->GetNumCompileUnits(); i++) {
285061da546Spatrick // Look for a matching source file in this CU.
286061da546Spatrick CompUnitSP cu_sp(module->GetCompileUnitAtIndex(i));
287061da546Spatrick if (cu_sp) {
288061da546Spatrick num_matches +=
289061da546Spatrick DumpFileLinesInCompUnit(strm, module, cu_sp.get(), file_spec);
290061da546Spatrick }
291061da546Spatrick }
292061da546Spatrick }
293061da546Spatrick return num_matches;
294061da546Spatrick }
295061da546Spatrick
296061da546Spatrick // Given an address and a list of modules, append the symbol contexts of all
297061da546Spatrick // line entries containing the address found in the modules and return the
298061da546Spatrick // 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)299061da546Spatrick size_t GetSymbolContextsForAddress(const ModuleList &module_list,
300061da546Spatrick lldb::addr_t addr,
301061da546Spatrick SymbolContextList &sc_list,
302061da546Spatrick StreamString &error_strm) {
303061da546Spatrick Address so_addr;
304061da546Spatrick size_t num_matches = 0;
305061da546Spatrick assert(module_list.GetSize() > 0);
306061da546Spatrick Target *target = m_exe_ctx.GetTargetPtr();
307061da546Spatrick if (target->GetSectionLoadList().IsEmpty()) {
308061da546Spatrick // The target isn't loaded yet, we need to lookup the file address in all
309061da546Spatrick // modules. Note: the module list option does not apply to addresses.
310061da546Spatrick const size_t num_modules = module_list.GetSize();
311061da546Spatrick for (size_t i = 0; i < num_modules; ++i) {
312061da546Spatrick ModuleSP module_sp(module_list.GetModuleAtIndex(i));
313061da546Spatrick if (!module_sp)
314061da546Spatrick continue;
315061da546Spatrick if (module_sp->ResolveFileAddress(addr, so_addr)) {
316061da546Spatrick SymbolContext sc;
317061da546Spatrick sc.Clear(true);
318061da546Spatrick if (module_sp->ResolveSymbolContextForAddress(
319061da546Spatrick so_addr, eSymbolContextEverything, sc) &
320061da546Spatrick eSymbolContextLineEntry) {
321061da546Spatrick sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false);
322061da546Spatrick ++num_matches;
323061da546Spatrick }
324061da546Spatrick }
325061da546Spatrick }
326061da546Spatrick if (num_matches == 0)
327061da546Spatrick error_strm.Printf("Source information for file address 0x%" PRIx64
328061da546Spatrick " not found in any modules.\n",
329061da546Spatrick addr);
330061da546Spatrick } else {
331061da546Spatrick // The target has some things loaded, resolve this address to a compile
332061da546Spatrick // unit + file + line and display
333061da546Spatrick if (target->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) {
334061da546Spatrick ModuleSP module_sp(so_addr.GetModule());
335061da546Spatrick // Check to make sure this module is in our list.
336061da546Spatrick if (module_sp && module_list.GetIndexForModule(module_sp.get()) !=
337061da546Spatrick LLDB_INVALID_INDEX32) {
338061da546Spatrick SymbolContext sc;
339061da546Spatrick sc.Clear(true);
340061da546Spatrick if (module_sp->ResolveSymbolContextForAddress(
341061da546Spatrick so_addr, eSymbolContextEverything, sc) &
342061da546Spatrick eSymbolContextLineEntry) {
343061da546Spatrick sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false);
344061da546Spatrick ++num_matches;
345061da546Spatrick } else {
346061da546Spatrick StreamString addr_strm;
347061da546Spatrick so_addr.Dump(&addr_strm, nullptr,
348061da546Spatrick Address::DumpStyleModuleWithFileAddress);
349061da546Spatrick error_strm.Printf(
350061da546Spatrick "Address 0x%" PRIx64 " resolves to %s, but there is"
351061da546Spatrick " no source information available for this address.\n",
352061da546Spatrick addr, addr_strm.GetData());
353061da546Spatrick }
354061da546Spatrick } else {
355061da546Spatrick StreamString addr_strm;
356061da546Spatrick so_addr.Dump(&addr_strm, nullptr,
357061da546Spatrick Address::DumpStyleModuleWithFileAddress);
358061da546Spatrick error_strm.Printf("Address 0x%" PRIx64
359061da546Spatrick " resolves to %s, but it cannot"
360061da546Spatrick " be found in any modules.\n",
361061da546Spatrick addr, addr_strm.GetData());
362061da546Spatrick }
363061da546Spatrick } else
364061da546Spatrick error_strm.Printf("Unable to resolve address 0x%" PRIx64 ".\n", addr);
365061da546Spatrick }
366061da546Spatrick return num_matches;
367061da546Spatrick }
368061da546Spatrick
369061da546Spatrick // Dump the line entries found in functions matching the name specified in
370061da546Spatrick // the option.
DumpLinesInFunctions(CommandReturnObject & result)371061da546Spatrick bool DumpLinesInFunctions(CommandReturnObject &result) {
372061da546Spatrick SymbolContextList sc_list_funcs;
373061da546Spatrick ConstString name(m_options.symbol_name.c_str());
374061da546Spatrick SymbolContextList sc_list_lines;
375061da546Spatrick Target *target = m_exe_ctx.GetTargetPtr();
376061da546Spatrick uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
377061da546Spatrick
378*f6aab3d8Srobert ModuleFunctionSearchOptions function_options;
379*f6aab3d8Srobert function_options.include_symbols = false;
380*f6aab3d8Srobert function_options.include_inlines = true;
381*f6aab3d8Srobert
382061da546Spatrick // Note: module_list can't be const& because FindFunctionSymbols isn't
383061da546Spatrick // const.
384061da546Spatrick ModuleList module_list =
385061da546Spatrick (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages();
386*f6aab3d8Srobert module_list.FindFunctions(name, eFunctionNameTypeAuto, function_options,
387*f6aab3d8Srobert sc_list_funcs);
388061da546Spatrick size_t num_matches = sc_list_funcs.GetSize();
389061da546Spatrick
390061da546Spatrick if (!num_matches) {
391061da546Spatrick // If we didn't find any functions with that name, try searching for
392061da546Spatrick // symbols that line up exactly with function addresses.
393061da546Spatrick SymbolContextList sc_list_symbols;
394061da546Spatrick module_list.FindFunctionSymbols(name, eFunctionNameTypeAuto,
395061da546Spatrick sc_list_symbols);
396061da546Spatrick size_t num_symbol_matches = sc_list_symbols.GetSize();
397061da546Spatrick for (size_t i = 0; i < num_symbol_matches; i++) {
398061da546Spatrick SymbolContext sc;
399061da546Spatrick sc_list_symbols.GetContextAtIndex(i, sc);
400061da546Spatrick if (sc.symbol && sc.symbol->ValueIsAddress()) {
401061da546Spatrick const Address &base_address = sc.symbol->GetAddressRef();
402061da546Spatrick Function *function = base_address.CalculateSymbolContextFunction();
403061da546Spatrick if (function) {
404061da546Spatrick sc_list_funcs.Append(SymbolContext(function));
405061da546Spatrick num_matches++;
406061da546Spatrick }
407061da546Spatrick }
408061da546Spatrick }
409061da546Spatrick }
410061da546Spatrick if (num_matches == 0) {
411061da546Spatrick result.AppendErrorWithFormat("Could not find function named \'%s\'.\n",
412061da546Spatrick m_options.symbol_name.c_str());
413061da546Spatrick return false;
414061da546Spatrick }
415061da546Spatrick for (size_t i = 0; i < num_matches; i++) {
416061da546Spatrick SymbolContext sc;
417061da546Spatrick sc_list_funcs.GetContextAtIndex(i, sc);
418061da546Spatrick bool context_found_for_symbol = false;
419061da546Spatrick // Loop through all the ranges in the function.
420061da546Spatrick AddressRange range;
421061da546Spatrick for (uint32_t r = 0;
422061da546Spatrick sc.GetAddressRange(eSymbolContextEverything, r,
423061da546Spatrick /*use_inline_block_range=*/true, range);
424061da546Spatrick ++r) {
425061da546Spatrick // Append the symbol contexts for each address in the range to
426061da546Spatrick // sc_list_lines.
427061da546Spatrick const Address &base_address = range.GetBaseAddress();
428061da546Spatrick const addr_t size = range.GetByteSize();
429061da546Spatrick lldb::addr_t start_addr = base_address.GetLoadAddress(target);
430061da546Spatrick if (start_addr == LLDB_INVALID_ADDRESS)
431061da546Spatrick start_addr = base_address.GetFileAddress();
432061da546Spatrick lldb::addr_t end_addr = start_addr + size;
433061da546Spatrick for (lldb::addr_t addr = start_addr; addr < end_addr;
434061da546Spatrick addr += addr_byte_size) {
435061da546Spatrick StreamString error_strm;
436061da546Spatrick if (!GetSymbolContextsForAddress(module_list, addr, sc_list_lines,
437061da546Spatrick error_strm))
438061da546Spatrick result.AppendWarningWithFormat("in symbol '%s': %s",
439061da546Spatrick sc.GetFunctionName().AsCString(),
440061da546Spatrick error_strm.GetData());
441061da546Spatrick else
442061da546Spatrick context_found_for_symbol = true;
443061da546Spatrick }
444061da546Spatrick }
445061da546Spatrick if (!context_found_for_symbol)
446061da546Spatrick result.AppendWarningWithFormat("Unable to find line information"
447061da546Spatrick " for matching symbol '%s'.\n",
448061da546Spatrick sc.GetFunctionName().AsCString());
449061da546Spatrick }
450061da546Spatrick if (sc_list_lines.GetSize() == 0) {
451061da546Spatrick result.AppendErrorWithFormat("No line information could be found"
452061da546Spatrick " for any symbols matching '%s'.\n",
453061da546Spatrick name.AsCString());
454061da546Spatrick return false;
455061da546Spatrick }
456061da546Spatrick FileSpec file_spec;
457061da546Spatrick if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list_lines,
458061da546Spatrick module_list, file_spec)) {
459061da546Spatrick result.AppendErrorWithFormat(
460061da546Spatrick "Unable to dump line information for symbol '%s'.\n",
461061da546Spatrick name.AsCString());
462061da546Spatrick return false;
463061da546Spatrick }
464061da546Spatrick return true;
465061da546Spatrick }
466061da546Spatrick
467061da546Spatrick // Dump the line entries found for the address specified in the option.
DumpLinesForAddress(CommandReturnObject & result)468061da546Spatrick bool DumpLinesForAddress(CommandReturnObject &result) {
469061da546Spatrick Target *target = m_exe_ctx.GetTargetPtr();
470061da546Spatrick SymbolContextList sc_list;
471061da546Spatrick
472061da546Spatrick StreamString error_strm;
473061da546Spatrick if (!GetSymbolContextsForAddress(target->GetImages(), m_options.address,
474061da546Spatrick sc_list, error_strm)) {
475061da546Spatrick result.AppendErrorWithFormat("%s.\n", error_strm.GetData());
476061da546Spatrick return false;
477061da546Spatrick }
478061da546Spatrick ModuleList module_list;
479061da546Spatrick FileSpec file_spec;
480061da546Spatrick if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list,
481061da546Spatrick module_list, file_spec)) {
482061da546Spatrick result.AppendErrorWithFormat("No modules contain load address 0x%" PRIx64
483061da546Spatrick ".\n",
484061da546Spatrick m_options.address);
485061da546Spatrick return false;
486061da546Spatrick }
487061da546Spatrick return true;
488061da546Spatrick }
489061da546Spatrick
490061da546Spatrick // Dump the line entries found in the file specified in the option.
DumpLinesForFile(CommandReturnObject & result)491061da546Spatrick bool DumpLinesForFile(CommandReturnObject &result) {
492061da546Spatrick FileSpec file_spec(m_options.file_name);
493061da546Spatrick const char *filename = m_options.file_name.c_str();
494061da546Spatrick Target *target = m_exe_ctx.GetTargetPtr();
495061da546Spatrick const ModuleList &module_list =
496061da546Spatrick (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages();
497061da546Spatrick
498061da546Spatrick bool displayed_something = false;
499061da546Spatrick const size_t num_modules = module_list.GetSize();
500061da546Spatrick for (uint32_t i = 0; i < num_modules; ++i) {
501061da546Spatrick // Dump lines for this module.
502061da546Spatrick Module *module = module_list.GetModulePointerAtIndex(i);
503061da546Spatrick assert(module);
504061da546Spatrick if (DumpFileLinesInModule(result.GetOutputStream(), module, file_spec))
505061da546Spatrick displayed_something = true;
506061da546Spatrick }
507061da546Spatrick if (!displayed_something) {
508061da546Spatrick result.AppendErrorWithFormat("No source filenames matched '%s'.\n",
509061da546Spatrick filename);
510061da546Spatrick return false;
511061da546Spatrick }
512061da546Spatrick return true;
513061da546Spatrick }
514061da546Spatrick
515061da546Spatrick // Dump the line entries for the current frame.
DumpLinesForFrame(CommandReturnObject & result)516061da546Spatrick bool DumpLinesForFrame(CommandReturnObject &result) {
517061da546Spatrick StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
518061da546Spatrick if (cur_frame == nullptr) {
519061da546Spatrick result.AppendError(
520061da546Spatrick "No selected frame to use to find the default source.");
521061da546Spatrick return false;
522061da546Spatrick } else if (!cur_frame->HasDebugInformation()) {
523061da546Spatrick result.AppendError("No debug info for the selected frame.");
524061da546Spatrick return false;
525061da546Spatrick } else {
526061da546Spatrick const SymbolContext &sc =
527061da546Spatrick cur_frame->GetSymbolContext(eSymbolContextLineEntry);
528061da546Spatrick SymbolContextList sc_list;
529061da546Spatrick sc_list.Append(sc);
530061da546Spatrick ModuleList module_list;
531061da546Spatrick FileSpec file_spec;
532061da546Spatrick if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list,
533061da546Spatrick module_list, file_spec)) {
534061da546Spatrick result.AppendError(
535061da546Spatrick "No source line info available for the selected frame.");
536061da546Spatrick return false;
537061da546Spatrick }
538061da546Spatrick }
539061da546Spatrick return true;
540061da546Spatrick }
541061da546Spatrick
DoExecute(Args & command,CommandReturnObject & result)542061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
543061da546Spatrick Target *target = m_exe_ctx.GetTargetPtr();
544061da546Spatrick if (target == nullptr) {
545061da546Spatrick target = GetDebugger().GetSelectedTarget().get();
546061da546Spatrick if (target == nullptr) {
547061da546Spatrick result.AppendError("invalid target, create a debug target using the "
548061da546Spatrick "'target create' command.");
549061da546Spatrick return false;
550061da546Spatrick }
551061da546Spatrick }
552061da546Spatrick
553061da546Spatrick uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
554061da546Spatrick result.GetOutputStream().SetAddressByteSize(addr_byte_size);
555061da546Spatrick result.GetErrorStream().SetAddressByteSize(addr_byte_size);
556061da546Spatrick
557061da546Spatrick // Collect the list of modules to search.
558061da546Spatrick m_module_list.Clear();
559061da546Spatrick if (!m_options.modules.empty()) {
560061da546Spatrick for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) {
561061da546Spatrick FileSpec module_file_spec(m_options.modules[i]);
562061da546Spatrick if (module_file_spec) {
563061da546Spatrick ModuleSpec module_spec(module_file_spec);
564061da546Spatrick target->GetImages().FindModules(module_spec, m_module_list);
565061da546Spatrick if (m_module_list.IsEmpty())
566061da546Spatrick result.AppendWarningWithFormat("No module found for '%s'.\n",
567061da546Spatrick m_options.modules[i].c_str());
568061da546Spatrick }
569061da546Spatrick }
570061da546Spatrick if (!m_module_list.GetSize()) {
571061da546Spatrick result.AppendError("No modules match the input.");
572061da546Spatrick return false;
573061da546Spatrick }
574061da546Spatrick } else if (target->GetImages().GetSize() == 0) {
575061da546Spatrick result.AppendError("The target has no associated executable images.");
576061da546Spatrick return false;
577061da546Spatrick }
578061da546Spatrick
579061da546Spatrick // Check the arguments to see what lines we should dump.
580061da546Spatrick if (!m_options.symbol_name.empty()) {
581061da546Spatrick // Print lines for symbol.
582061da546Spatrick if (DumpLinesInFunctions(result))
583061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
584061da546Spatrick else
585061da546Spatrick result.SetStatus(eReturnStatusFailed);
586061da546Spatrick } else if (m_options.address != LLDB_INVALID_ADDRESS) {
587061da546Spatrick // Print lines for an address.
588061da546Spatrick if (DumpLinesForAddress(result))
589061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
590061da546Spatrick else
591061da546Spatrick result.SetStatus(eReturnStatusFailed);
592061da546Spatrick } else if (!m_options.file_name.empty()) {
593061da546Spatrick // Dump lines for a file.
594061da546Spatrick if (DumpLinesForFile(result))
595061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
596061da546Spatrick else
597061da546Spatrick result.SetStatus(eReturnStatusFailed);
598061da546Spatrick } else {
599061da546Spatrick // Dump the line for the current frame.
600061da546Spatrick if (DumpLinesForFrame(result))
601061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
602061da546Spatrick else
603061da546Spatrick result.SetStatus(eReturnStatusFailed);
604061da546Spatrick }
605061da546Spatrick return result.Succeeded();
606061da546Spatrick }
607061da546Spatrick
608061da546Spatrick CommandOptions m_options;
609061da546Spatrick ModuleList m_module_list;
610061da546Spatrick };
611061da546Spatrick
612061da546Spatrick #pragma mark CommandObjectSourceList
613061da546Spatrick // CommandObjectSourceList
614061da546Spatrick #define LLDB_OPTIONS_source_list
615061da546Spatrick #include "CommandOptions.inc"
616061da546Spatrick
617061da546Spatrick class CommandObjectSourceList : public CommandObjectParsed {
618061da546Spatrick class CommandOptions : public Options {
619061da546Spatrick public:
620*f6aab3d8Srobert CommandOptions() = default;
621061da546Spatrick
622061da546Spatrick ~CommandOptions() override = default;
623061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)624061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
625061da546Spatrick ExecutionContext *execution_context) override {
626061da546Spatrick Status error;
627061da546Spatrick const int short_option = GetDefinitions()[option_idx].short_option;
628061da546Spatrick switch (short_option) {
629061da546Spatrick case 'l':
630061da546Spatrick if (option_arg.getAsInteger(0, start_line))
631061da546Spatrick error.SetErrorStringWithFormat("invalid line number: '%s'",
632061da546Spatrick option_arg.str().c_str());
633061da546Spatrick break;
634061da546Spatrick
635061da546Spatrick case 'c':
636061da546Spatrick if (option_arg.getAsInteger(0, num_lines))
637061da546Spatrick error.SetErrorStringWithFormat("invalid line count: '%s'",
638061da546Spatrick option_arg.str().c_str());
639061da546Spatrick break;
640061da546Spatrick
641061da546Spatrick case 'f':
642dda28197Spatrick file_name = std::string(option_arg);
643061da546Spatrick break;
644061da546Spatrick
645061da546Spatrick case 'n':
646dda28197Spatrick symbol_name = std::string(option_arg);
647061da546Spatrick break;
648061da546Spatrick
649061da546Spatrick case 'a': {
650061da546Spatrick address = OptionArgParser::ToAddress(execution_context, option_arg,
651061da546Spatrick LLDB_INVALID_ADDRESS, &error);
652061da546Spatrick } break;
653061da546Spatrick case 's':
654061da546Spatrick modules.push_back(std::string(option_arg));
655061da546Spatrick break;
656061da546Spatrick
657061da546Spatrick case 'b':
658061da546Spatrick show_bp_locs = true;
659061da546Spatrick break;
660061da546Spatrick case 'r':
661061da546Spatrick reverse = true;
662061da546Spatrick break;
663be691f3bSpatrick case 'y':
664be691f3bSpatrick {
665be691f3bSpatrick OptionValueFileColonLine value;
666be691f3bSpatrick Status fcl_err = value.SetValueFromString(option_arg);
667be691f3bSpatrick if (!fcl_err.Success()) {
668be691f3bSpatrick error.SetErrorStringWithFormat(
669be691f3bSpatrick "Invalid value for file:line specifier: %s",
670be691f3bSpatrick fcl_err.AsCString());
671be691f3bSpatrick } else {
672be691f3bSpatrick file_name = value.GetFileSpec().GetPath();
673be691f3bSpatrick start_line = value.GetLineNumber();
674be691f3bSpatrick // I don't see anything useful to do with a column number, but I don't
675be691f3bSpatrick // want to complain since someone may well have cut and pasted a
676be691f3bSpatrick // listing from somewhere that included a column.
677be691f3bSpatrick }
678be691f3bSpatrick } break;
679061da546Spatrick default:
680061da546Spatrick llvm_unreachable("Unimplemented option");
681061da546Spatrick }
682061da546Spatrick
683061da546Spatrick return error;
684061da546Spatrick }
685061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)686061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
687061da546Spatrick file_spec.Clear();
688061da546Spatrick file_name.clear();
689061da546Spatrick symbol_name.clear();
690061da546Spatrick address = LLDB_INVALID_ADDRESS;
691061da546Spatrick start_line = 0;
692061da546Spatrick num_lines = 0;
693061da546Spatrick show_bp_locs = false;
694061da546Spatrick reverse = false;
695061da546Spatrick modules.clear();
696061da546Spatrick }
697061da546Spatrick
GetDefinitions()698061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
699*f6aab3d8Srobert return llvm::ArrayRef(g_source_list_options);
700061da546Spatrick }
701061da546Spatrick
702061da546Spatrick // Instance variables to hold the values for command options.
703061da546Spatrick FileSpec file_spec;
704061da546Spatrick std::string file_name;
705061da546Spatrick std::string symbol_name;
706061da546Spatrick lldb::addr_t address;
707061da546Spatrick uint32_t start_line;
708061da546Spatrick uint32_t num_lines;
709061da546Spatrick std::vector<std::string> modules;
710061da546Spatrick bool show_bp_locs;
711061da546Spatrick bool reverse;
712061da546Spatrick };
713061da546Spatrick
714061da546Spatrick public:
CommandObjectSourceList(CommandInterpreter & interpreter)715061da546Spatrick CommandObjectSourceList(CommandInterpreter &interpreter)
716061da546Spatrick : CommandObjectParsed(interpreter, "source list",
717061da546Spatrick "Display source code for the current target "
718061da546Spatrick "process as specified by options.",
719*f6aab3d8Srobert nullptr, eCommandRequiresTarget) {}
720061da546Spatrick
721061da546Spatrick ~CommandObjectSourceList() override = default;
722061da546Spatrick
GetOptions()723061da546Spatrick Options *GetOptions() override { return &m_options; }
724061da546Spatrick
GetRepeatCommand(Args & current_command_args,uint32_t index)725*f6aab3d8Srobert std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,
726061da546Spatrick uint32_t index) override {
727061da546Spatrick // This is kind of gross, but the command hasn't been parsed yet so we
728061da546Spatrick // can't look at the option values for this invocation... I have to scan
729061da546Spatrick // the arguments directly.
730061da546Spatrick auto iter =
731061da546Spatrick llvm::find_if(current_command_args, [](const Args::ArgEntry &e) {
732061da546Spatrick return e.ref() == "-r" || e.ref() == "--reverse";
733061da546Spatrick });
734061da546Spatrick if (iter == current_command_args.end())
735*f6aab3d8Srobert return m_cmd_name;
736061da546Spatrick
737061da546Spatrick if (m_reverse_name.empty()) {
738061da546Spatrick m_reverse_name = m_cmd_name;
739061da546Spatrick m_reverse_name.append(" -r");
740061da546Spatrick }
741*f6aab3d8Srobert return m_reverse_name;
742061da546Spatrick }
743061da546Spatrick
744061da546Spatrick protected:
745061da546Spatrick struct SourceInfo {
746061da546Spatrick ConstString function;
747061da546Spatrick LineEntry line_entry;
748061da546Spatrick
SourceInfoCommandObjectSourceList::SourceInfo749061da546Spatrick SourceInfo(ConstString name, const LineEntry &line_entry)
750061da546Spatrick : function(name), line_entry(line_entry) {}
751061da546Spatrick
752*f6aab3d8Srobert SourceInfo() = default;
753061da546Spatrick
IsValidCommandObjectSourceList::SourceInfo754061da546Spatrick bool IsValid() const { return (bool)function && line_entry.IsValid(); }
755061da546Spatrick
operator ==CommandObjectSourceList::SourceInfo756061da546Spatrick bool operator==(const SourceInfo &rhs) const {
757061da546Spatrick return function == rhs.function &&
758061da546Spatrick line_entry.original_file == rhs.line_entry.original_file &&
759061da546Spatrick line_entry.line == rhs.line_entry.line;
760061da546Spatrick }
761061da546Spatrick
operator !=CommandObjectSourceList::SourceInfo762061da546Spatrick bool operator!=(const SourceInfo &rhs) const {
763061da546Spatrick return function != rhs.function ||
764061da546Spatrick line_entry.original_file != rhs.line_entry.original_file ||
765061da546Spatrick line_entry.line != rhs.line_entry.line;
766061da546Spatrick }
767061da546Spatrick
operator <CommandObjectSourceList::SourceInfo768061da546Spatrick bool operator<(const SourceInfo &rhs) const {
769061da546Spatrick if (function.GetCString() < rhs.function.GetCString())
770061da546Spatrick return true;
771061da546Spatrick if (line_entry.file.GetDirectory().GetCString() <
772061da546Spatrick rhs.line_entry.file.GetDirectory().GetCString())
773061da546Spatrick return true;
774061da546Spatrick if (line_entry.file.GetFilename().GetCString() <
775061da546Spatrick rhs.line_entry.file.GetFilename().GetCString())
776061da546Spatrick return true;
777061da546Spatrick if (line_entry.line < rhs.line_entry.line)
778061da546Spatrick return true;
779061da546Spatrick return false;
780061da546Spatrick }
781061da546Spatrick };
782061da546Spatrick
DisplayFunctionSource(const SymbolContext & sc,SourceInfo & source_info,CommandReturnObject & result)783061da546Spatrick size_t DisplayFunctionSource(const SymbolContext &sc, SourceInfo &source_info,
784061da546Spatrick CommandReturnObject &result) {
785061da546Spatrick if (!source_info.IsValid()) {
786061da546Spatrick source_info.function = sc.GetFunctionName();
787061da546Spatrick source_info.line_entry = sc.GetFunctionStartLineEntry();
788061da546Spatrick }
789061da546Spatrick
790061da546Spatrick if (sc.function) {
791061da546Spatrick Target *target = m_exe_ctx.GetTargetPtr();
792061da546Spatrick
793061da546Spatrick FileSpec start_file;
794061da546Spatrick uint32_t start_line;
795061da546Spatrick uint32_t end_line;
796061da546Spatrick FileSpec end_file;
797061da546Spatrick
798061da546Spatrick if (sc.block == nullptr) {
799061da546Spatrick // Not an inlined function
800061da546Spatrick sc.function->GetStartLineSourceInfo(start_file, start_line);
801061da546Spatrick if (start_line == 0) {
802061da546Spatrick result.AppendErrorWithFormat("Could not find line information for "
803061da546Spatrick "start of function: \"%s\".\n",
804061da546Spatrick source_info.function.GetCString());
805061da546Spatrick return 0;
806061da546Spatrick }
807061da546Spatrick sc.function->GetEndLineSourceInfo(end_file, end_line);
808061da546Spatrick } else {
809061da546Spatrick // We have an inlined function
810061da546Spatrick start_file = source_info.line_entry.file;
811061da546Spatrick start_line = source_info.line_entry.line;
812061da546Spatrick end_line = start_line + m_options.num_lines;
813061da546Spatrick }
814061da546Spatrick
815061da546Spatrick // This is a little hacky, but the first line table entry for a function
816061da546Spatrick // points to the "{" that starts the function block. It would be nice to
817061da546Spatrick // actually get the function declaration in there too. So back up a bit,
818061da546Spatrick // but not further than what you're going to display.
819061da546Spatrick uint32_t extra_lines;
820061da546Spatrick if (m_options.num_lines >= 10)
821061da546Spatrick extra_lines = 5;
822061da546Spatrick else
823061da546Spatrick extra_lines = m_options.num_lines / 2;
824061da546Spatrick uint32_t line_no;
825061da546Spatrick if (start_line <= extra_lines)
826061da546Spatrick line_no = 1;
827061da546Spatrick else
828061da546Spatrick line_no = start_line - extra_lines;
829061da546Spatrick
830061da546Spatrick // For fun, if the function is shorter than the number of lines we're
831061da546Spatrick // supposed to display, only display the function...
832061da546Spatrick if (end_line != 0) {
833061da546Spatrick if (m_options.num_lines > end_line - line_no)
834061da546Spatrick m_options.num_lines = end_line - line_no + extra_lines;
835061da546Spatrick }
836061da546Spatrick
837061da546Spatrick m_breakpoint_locations.Clear();
838061da546Spatrick
839061da546Spatrick if (m_options.show_bp_locs) {
840061da546Spatrick const bool show_inlines = true;
841061da546Spatrick m_breakpoint_locations.Reset(start_file, 0, show_inlines);
842061da546Spatrick SearchFilterForUnconstrainedSearches target_search_filter(
843061da546Spatrick m_exe_ctx.GetTargetSP());
844061da546Spatrick target_search_filter.Search(m_breakpoint_locations);
845061da546Spatrick }
846061da546Spatrick
847061da546Spatrick result.AppendMessageWithFormat("File: %s\n",
848061da546Spatrick start_file.GetPath().c_str());
849061da546Spatrick // We don't care about the column here.
850061da546Spatrick const uint32_t column = 0;
851061da546Spatrick return target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
852061da546Spatrick start_file, line_no, column, 0, m_options.num_lines, "",
853061da546Spatrick &result.GetOutputStream(), GetBreakpointLocations());
854061da546Spatrick } else {
855061da546Spatrick result.AppendErrorWithFormat(
856061da546Spatrick "Could not find function info for: \"%s\".\n",
857061da546Spatrick m_options.symbol_name.c_str());
858061da546Spatrick }
859061da546Spatrick return 0;
860061da546Spatrick }
861061da546Spatrick
862061da546Spatrick // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols
863061da546Spatrick // functions "take a possibly empty vector of strings which are names of
864061da546Spatrick // modules, and run the two search functions on the subset of the full module
865061da546Spatrick // list that matches the strings in the input vector". If we wanted to put
866061da546Spatrick // these somewhere, there should probably be a module-filter-list that can be
867061da546Spatrick // passed to the various ModuleList::Find* calls, which would either be a
868061da546Spatrick // vector of string names or a ModuleSpecList.
FindMatchingFunctions(Target * target,ConstString name,SymbolContextList & sc_list)869061da546Spatrick void FindMatchingFunctions(Target *target, ConstString name,
870061da546Spatrick SymbolContextList &sc_list) {
871061da546Spatrick // Displaying the source for a symbol:
872061da546Spatrick if (m_options.num_lines == 0)
873061da546Spatrick m_options.num_lines = 10;
874061da546Spatrick
875*f6aab3d8Srobert ModuleFunctionSearchOptions function_options;
876*f6aab3d8Srobert function_options.include_symbols = true;
877*f6aab3d8Srobert function_options.include_inlines = false;
878*f6aab3d8Srobert
879061da546Spatrick const size_t num_modules = m_options.modules.size();
880061da546Spatrick if (num_modules > 0) {
881061da546Spatrick ModuleList matching_modules;
882061da546Spatrick for (size_t i = 0; i < num_modules; ++i) {
883061da546Spatrick FileSpec module_file_spec(m_options.modules[i]);
884061da546Spatrick if (module_file_spec) {
885061da546Spatrick ModuleSpec module_spec(module_file_spec);
886061da546Spatrick matching_modules.Clear();
887061da546Spatrick target->GetImages().FindModules(module_spec, matching_modules);
888*f6aab3d8Srobert
889061da546Spatrick matching_modules.FindFunctions(name, eFunctionNameTypeAuto,
890*f6aab3d8Srobert function_options, sc_list);
891061da546Spatrick }
892061da546Spatrick }
893061da546Spatrick } else {
894061da546Spatrick target->GetImages().FindFunctions(name, eFunctionNameTypeAuto,
895*f6aab3d8Srobert function_options, sc_list);
896061da546Spatrick }
897061da546Spatrick }
898061da546Spatrick
FindMatchingFunctionSymbols(Target * target,ConstString name,SymbolContextList & sc_list)899061da546Spatrick void FindMatchingFunctionSymbols(Target *target, ConstString name,
900061da546Spatrick SymbolContextList &sc_list) {
901061da546Spatrick const size_t num_modules = m_options.modules.size();
902061da546Spatrick if (num_modules > 0) {
903061da546Spatrick ModuleList matching_modules;
904061da546Spatrick for (size_t i = 0; i < num_modules; ++i) {
905061da546Spatrick FileSpec module_file_spec(m_options.modules[i]);
906061da546Spatrick if (module_file_spec) {
907061da546Spatrick ModuleSpec module_spec(module_file_spec);
908061da546Spatrick matching_modules.Clear();
909061da546Spatrick target->GetImages().FindModules(module_spec, matching_modules);
910061da546Spatrick matching_modules.FindFunctionSymbols(name, eFunctionNameTypeAuto,
911061da546Spatrick sc_list);
912061da546Spatrick }
913061da546Spatrick }
914061da546Spatrick } else {
915061da546Spatrick target->GetImages().FindFunctionSymbols(name, eFunctionNameTypeAuto,
916061da546Spatrick sc_list);
917061da546Spatrick }
918061da546Spatrick }
919061da546Spatrick
DoExecute(Args & command,CommandReturnObject & result)920061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
921061da546Spatrick Target *target = m_exe_ctx.GetTargetPtr();
922061da546Spatrick
923061da546Spatrick if (!m_options.symbol_name.empty()) {
924061da546Spatrick SymbolContextList sc_list;
925061da546Spatrick ConstString name(m_options.symbol_name.c_str());
926061da546Spatrick
927061da546Spatrick // Displaying the source for a symbol. Search for function named name.
928061da546Spatrick FindMatchingFunctions(target, name, sc_list);
929061da546Spatrick size_t num_matches = sc_list.GetSize();
930061da546Spatrick if (!num_matches) {
931061da546Spatrick // If we didn't find any functions with that name, try searching for
932061da546Spatrick // symbols that line up exactly with function addresses.
933061da546Spatrick SymbolContextList sc_list_symbols;
934061da546Spatrick FindMatchingFunctionSymbols(target, name, sc_list_symbols);
935061da546Spatrick size_t num_symbol_matches = sc_list_symbols.GetSize();
936061da546Spatrick
937061da546Spatrick for (size_t i = 0; i < num_symbol_matches; i++) {
938061da546Spatrick SymbolContext sc;
939061da546Spatrick sc_list_symbols.GetContextAtIndex(i, sc);
940061da546Spatrick if (sc.symbol && sc.symbol->ValueIsAddress()) {
941061da546Spatrick const Address &base_address = sc.symbol->GetAddressRef();
942061da546Spatrick Function *function = base_address.CalculateSymbolContextFunction();
943061da546Spatrick if (function) {
944061da546Spatrick sc_list.Append(SymbolContext(function));
945061da546Spatrick num_matches++;
946061da546Spatrick break;
947061da546Spatrick }
948061da546Spatrick }
949061da546Spatrick }
950061da546Spatrick }
951061da546Spatrick
952061da546Spatrick if (num_matches == 0) {
953061da546Spatrick result.AppendErrorWithFormat("Could not find function named: \"%s\".\n",
954061da546Spatrick m_options.symbol_name.c_str());
955061da546Spatrick return false;
956061da546Spatrick }
957061da546Spatrick
958061da546Spatrick if (num_matches > 1) {
959061da546Spatrick std::set<SourceInfo> source_match_set;
960061da546Spatrick
961061da546Spatrick bool displayed_something = false;
962061da546Spatrick for (size_t i = 0; i < num_matches; i++) {
963061da546Spatrick SymbolContext sc;
964061da546Spatrick sc_list.GetContextAtIndex(i, sc);
965061da546Spatrick SourceInfo source_info(sc.GetFunctionName(),
966061da546Spatrick sc.GetFunctionStartLineEntry());
967061da546Spatrick
968061da546Spatrick if (source_info.IsValid()) {
969061da546Spatrick if (source_match_set.find(source_info) == source_match_set.end()) {
970061da546Spatrick source_match_set.insert(source_info);
971061da546Spatrick if (DisplayFunctionSource(sc, source_info, result))
972061da546Spatrick displayed_something = true;
973061da546Spatrick }
974061da546Spatrick }
975061da546Spatrick }
976061da546Spatrick
977061da546Spatrick if (displayed_something)
978061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
979061da546Spatrick else
980061da546Spatrick result.SetStatus(eReturnStatusFailed);
981061da546Spatrick } else {
982061da546Spatrick SymbolContext sc;
983061da546Spatrick sc_list.GetContextAtIndex(0, sc);
984061da546Spatrick SourceInfo source_info;
985061da546Spatrick
986061da546Spatrick if (DisplayFunctionSource(sc, source_info, result)) {
987061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
988061da546Spatrick } else {
989061da546Spatrick result.SetStatus(eReturnStatusFailed);
990061da546Spatrick }
991061da546Spatrick }
992061da546Spatrick return result.Succeeded();
993061da546Spatrick } else if (m_options.address != LLDB_INVALID_ADDRESS) {
994061da546Spatrick Address so_addr;
995061da546Spatrick StreamString error_strm;
996061da546Spatrick SymbolContextList sc_list;
997061da546Spatrick
998061da546Spatrick if (target->GetSectionLoadList().IsEmpty()) {
999061da546Spatrick // The target isn't loaded yet, we need to lookup the file address in
1000061da546Spatrick // all modules
1001061da546Spatrick const ModuleList &module_list = target->GetImages();
1002061da546Spatrick const size_t num_modules = module_list.GetSize();
1003061da546Spatrick for (size_t i = 0; i < num_modules; ++i) {
1004061da546Spatrick ModuleSP module_sp(module_list.GetModuleAtIndex(i));
1005061da546Spatrick if (module_sp &&
1006061da546Spatrick module_sp->ResolveFileAddress(m_options.address, so_addr)) {
1007061da546Spatrick SymbolContext sc;
1008061da546Spatrick sc.Clear(true);
1009061da546Spatrick if (module_sp->ResolveSymbolContextForAddress(
1010061da546Spatrick so_addr, eSymbolContextEverything, sc) &
1011061da546Spatrick eSymbolContextLineEntry)
1012061da546Spatrick sc_list.Append(sc);
1013061da546Spatrick }
1014061da546Spatrick }
1015061da546Spatrick
1016061da546Spatrick if (sc_list.GetSize() == 0) {
1017061da546Spatrick result.AppendErrorWithFormat(
1018061da546Spatrick "no modules have source information for file address 0x%" PRIx64
1019061da546Spatrick ".\n",
1020061da546Spatrick m_options.address);
1021061da546Spatrick return false;
1022061da546Spatrick }
1023061da546Spatrick } else {
1024061da546Spatrick // The target has some things loaded, resolve this address to a compile
1025061da546Spatrick // unit + file + line and display
1026061da546Spatrick if (target->GetSectionLoadList().ResolveLoadAddress(m_options.address,
1027061da546Spatrick so_addr)) {
1028061da546Spatrick ModuleSP module_sp(so_addr.GetModule());
1029061da546Spatrick if (module_sp) {
1030061da546Spatrick SymbolContext sc;
1031061da546Spatrick sc.Clear(true);
1032061da546Spatrick if (module_sp->ResolveSymbolContextForAddress(
1033061da546Spatrick so_addr, eSymbolContextEverything, sc) &
1034061da546Spatrick eSymbolContextLineEntry) {
1035061da546Spatrick sc_list.Append(sc);
1036061da546Spatrick } else {
1037061da546Spatrick so_addr.Dump(&error_strm, nullptr,
1038061da546Spatrick Address::DumpStyleModuleWithFileAddress);
1039061da546Spatrick result.AppendErrorWithFormat("address resolves to %s, but there "
1040061da546Spatrick "is no line table information "
1041061da546Spatrick "available for this address.\n",
1042061da546Spatrick error_strm.GetData());
1043061da546Spatrick return false;
1044061da546Spatrick }
1045061da546Spatrick }
1046061da546Spatrick }
1047061da546Spatrick
1048061da546Spatrick if (sc_list.GetSize() == 0) {
1049061da546Spatrick result.AppendErrorWithFormat(
1050061da546Spatrick "no modules contain load address 0x%" PRIx64 ".\n",
1051061da546Spatrick m_options.address);
1052061da546Spatrick return false;
1053061da546Spatrick }
1054061da546Spatrick }
1055061da546Spatrick uint32_t num_matches = sc_list.GetSize();
1056061da546Spatrick for (uint32_t i = 0; i < num_matches; ++i) {
1057061da546Spatrick SymbolContext sc;
1058061da546Spatrick sc_list.GetContextAtIndex(i, sc);
1059061da546Spatrick if (sc.comp_unit) {
1060061da546Spatrick if (m_options.show_bp_locs) {
1061061da546Spatrick m_breakpoint_locations.Clear();
1062061da546Spatrick const bool show_inlines = true;
1063061da546Spatrick m_breakpoint_locations.Reset(sc.comp_unit->GetPrimaryFile(), 0,
1064061da546Spatrick show_inlines);
1065061da546Spatrick SearchFilterForUnconstrainedSearches target_search_filter(
1066061da546Spatrick target->shared_from_this());
1067061da546Spatrick target_search_filter.Search(m_breakpoint_locations);
1068061da546Spatrick }
1069061da546Spatrick
1070061da546Spatrick bool show_fullpaths = true;
1071061da546Spatrick bool show_module = true;
1072061da546Spatrick bool show_inlined_frames = true;
1073061da546Spatrick const bool show_function_arguments = true;
1074061da546Spatrick const bool show_function_name = true;
1075061da546Spatrick sc.DumpStopContext(&result.GetOutputStream(),
1076061da546Spatrick m_exe_ctx.GetBestExecutionContextScope(),
1077061da546Spatrick sc.line_entry.range.GetBaseAddress(),
1078061da546Spatrick show_fullpaths, show_module, show_inlined_frames,
1079061da546Spatrick show_function_arguments, show_function_name);
1080061da546Spatrick result.GetOutputStream().EOL();
1081061da546Spatrick
1082061da546Spatrick if (m_options.num_lines == 0)
1083061da546Spatrick m_options.num_lines = 10;
1084061da546Spatrick
1085061da546Spatrick size_t lines_to_back_up =
1086061da546Spatrick m_options.num_lines >= 10 ? 5 : m_options.num_lines / 2;
1087061da546Spatrick
1088061da546Spatrick const uint32_t column =
1089061da546Spatrick (GetDebugger().GetStopShowColumn() != eStopShowColumnNone)
1090061da546Spatrick ? sc.line_entry.column
1091061da546Spatrick : 0;
1092061da546Spatrick target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
1093061da546Spatrick sc.comp_unit->GetPrimaryFile(), sc.line_entry.line, column,
1094061da546Spatrick lines_to_back_up, m_options.num_lines - lines_to_back_up, "->",
1095061da546Spatrick &result.GetOutputStream(), GetBreakpointLocations());
1096061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1097061da546Spatrick }
1098061da546Spatrick }
1099061da546Spatrick } else if (m_options.file_name.empty()) {
1100061da546Spatrick // Last valid source manager context, or the current frame if no valid
1101061da546Spatrick // last context in source manager. One little trick here, if you type the
1102061da546Spatrick // exact same list command twice in a row, it is more likely because you
1103061da546Spatrick // typed it once, then typed it again
1104061da546Spatrick if (m_options.start_line == 0) {
1105061da546Spatrick if (target->GetSourceManager().DisplayMoreWithLineNumbers(
1106061da546Spatrick &result.GetOutputStream(), m_options.num_lines,
1107061da546Spatrick m_options.reverse, GetBreakpointLocations())) {
1108061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1109061da546Spatrick }
1110061da546Spatrick } else {
1111061da546Spatrick if (m_options.num_lines == 0)
1112061da546Spatrick m_options.num_lines = 10;
1113061da546Spatrick
1114061da546Spatrick if (m_options.show_bp_locs) {
1115061da546Spatrick SourceManager::FileSP last_file_sp(
1116061da546Spatrick target->GetSourceManager().GetLastFile());
1117061da546Spatrick if (last_file_sp) {
1118061da546Spatrick const bool show_inlines = true;
1119061da546Spatrick m_breakpoint_locations.Reset(last_file_sp->GetFileSpec(), 0,
1120061da546Spatrick show_inlines);
1121061da546Spatrick SearchFilterForUnconstrainedSearches target_search_filter(
1122061da546Spatrick target->shared_from_this());
1123061da546Spatrick target_search_filter.Search(m_breakpoint_locations);
1124061da546Spatrick }
1125061da546Spatrick } else
1126061da546Spatrick m_breakpoint_locations.Clear();
1127061da546Spatrick
1128061da546Spatrick const uint32_t column = 0;
1129061da546Spatrick if (target->GetSourceManager()
1130061da546Spatrick .DisplaySourceLinesWithLineNumbersUsingLastFile(
1131061da546Spatrick m_options.start_line, // Line to display
1132061da546Spatrick m_options.num_lines, // Lines after line to
1133061da546Spatrick UINT32_MAX, // Don't mark "line"
1134061da546Spatrick column,
1135061da546Spatrick "", // Don't mark "line"
1136061da546Spatrick &result.GetOutputStream(), GetBreakpointLocations())) {
1137061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1138061da546Spatrick }
1139061da546Spatrick }
1140061da546Spatrick } else {
1141061da546Spatrick const char *filename = m_options.file_name.c_str();
1142061da546Spatrick
1143061da546Spatrick bool check_inlines = false;
1144061da546Spatrick SymbolContextList sc_list;
1145061da546Spatrick size_t num_matches = 0;
1146061da546Spatrick
1147061da546Spatrick if (!m_options.modules.empty()) {
1148061da546Spatrick ModuleList matching_modules;
1149061da546Spatrick for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) {
1150061da546Spatrick FileSpec module_file_spec(m_options.modules[i]);
1151061da546Spatrick if (module_file_spec) {
1152061da546Spatrick ModuleSpec module_spec(module_file_spec);
1153061da546Spatrick matching_modules.Clear();
1154061da546Spatrick target->GetImages().FindModules(module_spec, matching_modules);
1155061da546Spatrick num_matches += matching_modules.ResolveSymbolContextForFilePath(
1156061da546Spatrick filename, 0, check_inlines,
1157061da546Spatrick SymbolContextItem(eSymbolContextModule |
1158061da546Spatrick eSymbolContextCompUnit),
1159061da546Spatrick sc_list);
1160061da546Spatrick }
1161061da546Spatrick }
1162061da546Spatrick } else {
1163061da546Spatrick num_matches = target->GetImages().ResolveSymbolContextForFilePath(
1164061da546Spatrick filename, 0, check_inlines,
1165061da546Spatrick eSymbolContextModule | eSymbolContextCompUnit, sc_list);
1166061da546Spatrick }
1167061da546Spatrick
1168061da546Spatrick if (num_matches == 0) {
1169061da546Spatrick result.AppendErrorWithFormat("Could not find source file \"%s\".\n",
1170061da546Spatrick m_options.file_name.c_str());
1171061da546Spatrick return false;
1172061da546Spatrick }
1173061da546Spatrick
1174061da546Spatrick if (num_matches > 1) {
1175061da546Spatrick bool got_multiple = false;
1176061da546Spatrick CompileUnit *test_cu = nullptr;
1177061da546Spatrick
1178061da546Spatrick for (unsigned i = 0; i < num_matches; i++) {
1179061da546Spatrick SymbolContext sc;
1180061da546Spatrick sc_list.GetContextAtIndex(i, sc);
1181061da546Spatrick if (sc.comp_unit) {
1182061da546Spatrick if (test_cu) {
1183061da546Spatrick if (test_cu != sc.comp_unit)
1184061da546Spatrick got_multiple = true;
1185061da546Spatrick break;
1186061da546Spatrick } else
1187061da546Spatrick test_cu = sc.comp_unit;
1188061da546Spatrick }
1189061da546Spatrick }
1190061da546Spatrick if (got_multiple) {
1191061da546Spatrick result.AppendErrorWithFormat(
1192061da546Spatrick "Multiple source files found matching: \"%s.\"\n",
1193061da546Spatrick m_options.file_name.c_str());
1194061da546Spatrick return false;
1195061da546Spatrick }
1196061da546Spatrick }
1197061da546Spatrick
1198061da546Spatrick SymbolContext sc;
1199061da546Spatrick if (sc_list.GetContextAtIndex(0, sc)) {
1200061da546Spatrick if (sc.comp_unit) {
1201061da546Spatrick if (m_options.show_bp_locs) {
1202061da546Spatrick const bool show_inlines = true;
1203061da546Spatrick m_breakpoint_locations.Reset(sc.comp_unit->GetPrimaryFile(), 0,
1204061da546Spatrick show_inlines);
1205061da546Spatrick SearchFilterForUnconstrainedSearches target_search_filter(
1206061da546Spatrick target->shared_from_this());
1207061da546Spatrick target_search_filter.Search(m_breakpoint_locations);
1208061da546Spatrick } else
1209061da546Spatrick m_breakpoint_locations.Clear();
1210061da546Spatrick
1211061da546Spatrick if (m_options.num_lines == 0)
1212061da546Spatrick m_options.num_lines = 10;
1213061da546Spatrick const uint32_t column = 0;
1214061da546Spatrick target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
1215061da546Spatrick sc.comp_unit->GetPrimaryFile(), m_options.start_line, column, 0,
1216061da546Spatrick m_options.num_lines, "", &result.GetOutputStream(),
1217061da546Spatrick GetBreakpointLocations());
1218061da546Spatrick
1219061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1220061da546Spatrick } else {
1221061da546Spatrick result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n",
1222061da546Spatrick m_options.file_name.c_str());
1223061da546Spatrick return false;
1224061da546Spatrick }
1225061da546Spatrick }
1226061da546Spatrick }
1227061da546Spatrick return result.Succeeded();
1228061da546Spatrick }
1229061da546Spatrick
GetBreakpointLocations()1230061da546Spatrick const SymbolContextList *GetBreakpointLocations() {
1231061da546Spatrick if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0)
1232061da546Spatrick return &m_breakpoint_locations.GetFileLineMatches();
1233061da546Spatrick return nullptr;
1234061da546Spatrick }
1235061da546Spatrick
1236061da546Spatrick CommandOptions m_options;
1237061da546Spatrick FileLineResolver m_breakpoint_locations;
1238061da546Spatrick std::string m_reverse_name;
1239061da546Spatrick };
1240061da546Spatrick
1241061da546Spatrick #pragma mark CommandObjectMultiwordSource
1242061da546Spatrick // CommandObjectMultiwordSource
1243061da546Spatrick
CommandObjectMultiwordSource(CommandInterpreter & interpreter)1244061da546Spatrick CommandObjectMultiwordSource::CommandObjectMultiwordSource(
1245061da546Spatrick CommandInterpreter &interpreter)
1246061da546Spatrick : CommandObjectMultiword(interpreter, "source",
1247061da546Spatrick "Commands for examining "
1248061da546Spatrick "source code described by "
1249061da546Spatrick "debug information for the "
1250061da546Spatrick "current target process.",
1251061da546Spatrick "source <subcommand> [<subcommand-options>]") {
1252061da546Spatrick LoadSubCommand("info",
1253061da546Spatrick CommandObjectSP(new CommandObjectSourceInfo(interpreter)));
1254061da546Spatrick LoadSubCommand("list",
1255061da546Spatrick CommandObjectSP(new CommandObjectSourceList(interpreter)));
1256061da546Spatrick }
1257061da546Spatrick
1258061da546Spatrick CommandObjectMultiwordSource::~CommandObjectMultiwordSource() = default;
1259