blob: c03c724ec3621c9100b6fa1162d6f57b2b3c1cd0 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- CommandObjectSource.cpp ---------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "CommandObjectSource.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
Greg Clayton66111032010-06-23 01:19:29 +000016#include "lldb/Core/Debugger.h"
Greg Clayton176761e2011-04-19 04:19:37 +000017#include "lldb/Core/FileLineResolver.h"
Greg Claytonc1a9ecd2012-12-07 00:19:47 +000018#include "lldb/Core/Module.h"
Greg Clayton1f746072012-08-29 21:13:06 +000019#include "lldb/Core/ModuleSpec.h"
Greg Clayton176761e2011-04-19 04:19:37 +000020#include "lldb/Core/SourceManager.h"
Greg Clayton53239f02011-02-08 05:05:52 +000021#include "lldb/Host/FileSpec.h"
Vince Harron5275aaa2015-01-15 20:08:35 +000022#include "lldb/Host/StringConvert.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000023#include "lldb/Interpreter/CommandCompletions.h"
24#include "lldb/Interpreter/CommandInterpreter.h"
25#include "lldb/Interpreter/CommandReturnObject.h"
26#include "lldb/Interpreter/Options.h"
Greg Clayton1f746072012-08-29 21:13:06 +000027#include "lldb/Symbol/CompileUnit.h"
28#include "lldb/Symbol/Function.h"
Michael Sartaincc791bb2013-07-11 16:40:56 +000029#include "lldb/Symbol/Symbol.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000030#include "lldb/Target/Process.h"
Greg Claytond5944cd2013-12-06 01:12:00 +000031#include "lldb/Target/SectionLoadList.h"
Dawn Perchik954b40b2016-01-05 19:51:51 +000032#include "lldb/Target/StackFrame.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000033#include "lldb/Target/TargetList.h"
34
35using namespace lldb;
36using namespace lldb_private;
37
Dawn Perchik954b40b2016-01-05 19:51:51 +000038#pragma mark CommandObjectSourceInfo
39//----------------------------------------------------------------------
40// CommandObjectSourceInfo - debug line entries dumping command
41//----------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +000042
Zachary Turner1f0f5b52016-09-22 20:22:55 +000043static OptionDefinition g_source_info_options[] = {
44 // clang-format off
45 { LLDB_OPT_SET_ALL, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "The number of line entries to display." },
46 { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "shlib", 's', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Look up the source in the given module or shared library (can be specified more than once)." },
47 { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source." },
48 { LLDB_OPT_SET_1, false, "line", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLineNum, "The line number at which to start the displaying lines." },
49 { LLDB_OPT_SET_1, false, "end-line", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLineNum, "The line number at which to stop displaying lines." },
50 { LLDB_OPT_SET_2, false, "name", 'n', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSymbolCompletion, eArgTypeSymbol, "The name of a function whose source to display." },
51 { LLDB_OPT_SET_3, false, "address", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddressOrExpression, "Lookup the address and display the source information for the corresponding file and line." },
52 // clang-format on
53};
54
Kate Stoneb9c1b512016-09-06 20:57:50 +000055class CommandObjectSourceInfo : public CommandObjectParsed {
56 class CommandOptions : public Options {
57 public:
58 CommandOptions() : Options() {}
Chris Lattner30fdc8d2010-06-08 16:52:24 +000059
Kate Stoneb9c1b512016-09-06 20:57:50 +000060 ~CommandOptions() override = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000061
Kate Stoneb9c1b512016-09-06 20:57:50 +000062 Error SetOptionValue(uint32_t option_idx, const char *option_arg,
63 ExecutionContext *execution_context) override {
64 Error error;
Zachary Turner1f0f5b52016-09-22 20:22:55 +000065 const int short_option = GetDefinitions()[option_idx].short_option;
Kate Stoneb9c1b512016-09-06 20:57:50 +000066 switch (short_option) {
67 case 'l':
68 start_line = StringConvert::ToUInt32(option_arg, 0);
69 if (start_line == 0)
70 error.SetErrorStringWithFormat("invalid line number: '%s'",
71 option_arg);
72 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000073
Kate Stoneb9c1b512016-09-06 20:57:50 +000074 case 'e':
75 end_line = StringConvert::ToUInt32(option_arg, 0);
76 if (end_line == 0)
77 error.SetErrorStringWithFormat("invalid line number: '%s'",
78 option_arg);
79 break;
Jim Inghamebc09c32010-07-07 03:36:20 +000080
Kate Stoneb9c1b512016-09-06 20:57:50 +000081 case 'c':
82 num_lines = StringConvert::ToUInt32(option_arg, 0);
83 if (num_lines == 0)
84 error.SetErrorStringWithFormat("invalid line count: '%s'",
85 option_arg);
86 break;
Dawn Perchik954b40b2016-01-05 19:51:51 +000087
Kate Stoneb9c1b512016-09-06 20:57:50 +000088 case 'f':
89 file_name = option_arg;
90 break;
Dawn Perchik954b40b2016-01-05 19:51:51 +000091
Kate Stoneb9c1b512016-09-06 20:57:50 +000092 case 'n':
93 symbol_name = option_arg;
94 break;
Dawn Perchik954b40b2016-01-05 19:51:51 +000095
Kate Stoneb9c1b512016-09-06 20:57:50 +000096 case 'a': {
97 address = Args::StringToAddress(execution_context, option_arg,
98 LLDB_INVALID_ADDRESS, &error);
99 } break;
100 case 's':
101 modules.push_back(std::string(option_arg));
102 break;
103 default:
104 error.SetErrorStringWithFormat("unrecognized short option '%c'",
105 short_option);
106 break;
107 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000108
Kate Stoneb9c1b512016-09-06 20:57:50 +0000109 return error;
110 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000111
Kate Stoneb9c1b512016-09-06 20:57:50 +0000112 void OptionParsingStarting(ExecutionContext *execution_context) override {
113 file_spec.Clear();
114 file_name.clear();
115 symbol_name.clear();
116 address = LLDB_INVALID_ADDRESS;
117 start_line = 0;
118 end_line = 0;
119 num_lines = 0;
120 modules.clear();
121 }
Jim Inghamebc09c32010-07-07 03:36:20 +0000122
Zachary Turner1f0f5b52016-09-22 20:22:55 +0000123 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
124 return g_source_info_options;
125 }
Jim Inghamebc09c32010-07-07 03:36:20 +0000126
Kate Stoneb9c1b512016-09-06 20:57:50 +0000127 // Instance variables to hold the values for command options.
128 FileSpec file_spec;
129 std::string file_name;
130 std::string symbol_name;
131 lldb::addr_t address;
132 uint32_t start_line;
133 uint32_t end_line;
134 uint32_t num_lines;
135 STLStringArray modules;
136 };
Dawn Perchik954b40b2016-01-05 19:51:51 +0000137
138public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000139 CommandObjectSourceInfo(CommandInterpreter &interpreter)
140 : CommandObjectParsed(
141 interpreter, "source info",
142 "Display source line information for the current target "
143 "process. Defaults to instruction pointer in current stack "
144 "frame.",
145 nullptr, eCommandRequiresTarget),
146 m_options() {}
Jim Inghamebc09c32010-07-07 03:36:20 +0000147
Kate Stoneb9c1b512016-09-06 20:57:50 +0000148 ~CommandObjectSourceInfo() override = default;
Jim Inghamebc09c32010-07-07 03:36:20 +0000149
Kate Stoneb9c1b512016-09-06 20:57:50 +0000150 Options *GetOptions() override { return &m_options; }
Jim Inghamebc09c32010-07-07 03:36:20 +0000151
Jim Ingham5a988412012-06-08 21:56:10 +0000152protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000153 // Dump the line entries in each symbol context.
154 // Return the number of entries found.
155 // If module_list is set, only dump lines contained in one of the modules.
156 // If file_spec is set, only dump lines in the file.
157 // If the start_line option was specified, don't print lines less than
158 // start_line.
159 // If the end_line option was specified, don't print lines greater than
160 // end_line.
161 // If the num_lines option was specified, dont print more than num_lines
162 // entries.
163 uint32_t DumpLinesInSymbolContexts(Stream &strm,
164 const SymbolContextList &sc_list,
165 const ModuleList &module_list,
166 const FileSpec &file_spec) {
167 uint32_t start_line = m_options.start_line;
168 uint32_t end_line = m_options.end_line;
169 uint32_t num_lines = m_options.num_lines;
170 Target *target = m_exe_ctx.GetTargetPtr();
Dawn Perchik954b40b2016-01-05 19:51:51 +0000171
Kate Stoneb9c1b512016-09-06 20:57:50 +0000172 uint32_t num_matches = 0;
173 bool has_path = false;
174 if (file_spec) {
175 assert(file_spec.GetFilename().AsCString());
176 has_path = (file_spec.GetDirectory().AsCString() != nullptr);
Dawn Perchik954b40b2016-01-05 19:51:51 +0000177 }
178
Kate Stoneb9c1b512016-09-06 20:57:50 +0000179 // Dump all the line entries for the file in the list.
180 ConstString last_module_file_name;
181 uint32_t num_scs = sc_list.GetSize();
182 for (uint32_t i = 0; i < num_scs; ++i) {
183 SymbolContext sc;
184 sc_list.GetContextAtIndex(i, sc);
185 if (sc.comp_unit) {
186 Module *module = sc.module_sp.get();
187 CompileUnit *cu = sc.comp_unit;
188 const LineEntry &line_entry = sc.line_entry;
189 assert(module && cu);
Dawn Perchik954b40b2016-01-05 19:51:51 +0000190
Kate Stoneb9c1b512016-09-06 20:57:50 +0000191 // Are we looking for specific modules, files or lines?
192 if (module_list.GetSize() &&
193 module_list.GetIndexForModule(module) == LLDB_INVALID_INDEX32)
194 continue;
195 if (file_spec &&
196 !lldb_private::FileSpec::Equal(file_spec, line_entry.file,
197 has_path))
198 continue;
199 if (start_line > 0 && line_entry.line < start_line)
200 continue;
201 if (end_line > 0 && line_entry.line > end_line)
202 continue;
203 if (num_lines > 0 && num_matches > num_lines)
204 continue;
205
206 // Print a new header if the module changed.
207 const ConstString &module_file_name =
208 module->GetFileSpec().GetFilename();
209 assert(module_file_name);
210 if (module_file_name != last_module_file_name) {
211 if (num_matches > 0)
212 strm << "\n\n";
213 strm << "Lines found in module `" << module_file_name << "\n";
214 }
215 // Dump the line entry.
216 line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu,
217 target, /*show_address_only=*/false);
218 strm << "\n";
219 last_module_file_name = module_file_name;
220 num_matches++;
221 }
222 }
223 return num_matches;
224 }
225
226 // Dump the requested line entries for the file in the compilation unit.
227 // Return the number of entries found.
228 // If module_list is set, only dump lines contained in one of the modules.
229 // If the start_line option was specified, don't print lines less than
230 // start_line.
231 // If the end_line option was specified, don't print lines greater than
232 // end_line.
233 // If the num_lines option was specified, dont print more than num_lines
234 // entries.
235 uint32_t DumpFileLinesInCompUnit(Stream &strm, Module *module,
236 CompileUnit *cu, const FileSpec &file_spec) {
237 uint32_t start_line = m_options.start_line;
238 uint32_t end_line = m_options.end_line;
239 uint32_t num_lines = m_options.num_lines;
240 Target *target = m_exe_ctx.GetTargetPtr();
241
242 uint32_t num_matches = 0;
243 assert(module);
244 if (cu) {
245 assert(file_spec.GetFilename().AsCString());
246 bool has_path = (file_spec.GetDirectory().AsCString() != nullptr);
247 const FileSpecList &cu_file_list = cu->GetSupportFiles();
248 size_t file_idx = cu_file_list.FindFileIndex(0, file_spec, has_path);
249 if (file_idx != UINT32_MAX) {
250 // Update the file to how it appears in the CU.
251 const FileSpec &cu_file_spec =
252 cu_file_list.GetFileSpecAtIndex(file_idx);
253
254 // Dump all matching lines at or above start_line for the file in the
255 // CU.
256 const ConstString &file_spec_name = file_spec.GetFilename();
257 const ConstString &module_file_name =
258 module->GetFileSpec().GetFilename();
259 bool cu_header_printed = false;
260 uint32_t line = start_line;
261 while (true) {
262 LineEntry line_entry;
263
264 // Find the lowest index of a line entry with a line equal to
265 // or higher than 'line'.
266 uint32_t start_idx = 0;
267 start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec,
268 /*exact=*/false, &line_entry);
269 if (start_idx == UINT32_MAX)
270 // No more line entries for our file in this CU.
271 break;
272
273 if (end_line > 0 && line_entry.line > end_line)
274 break;
275
276 // Loop through to find any other entries for this line, dumping each.
277 line = line_entry.line;
278 do {
279 num_matches++;
280 if (num_lines > 0 && num_matches > num_lines)
281 break;
282 assert(lldb_private::FileSpec::Equal(cu_file_spec, line_entry.file,
283 has_path));
284 if (!cu_header_printed) {
285 if (num_matches > 0)
286 strm << "\n\n";
287 strm << "Lines found for file " << file_spec_name
288 << " in compilation unit " << cu->GetFilename() << " in `"
289 << module_file_name << "\n";
290 cu_header_printed = true;
Dawn Perchik954b40b2016-01-05 19:51:51 +0000291 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000292 line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu,
293 target, /*show_address_only=*/false);
294 strm << "\n";
295
296 // Anymore after this one?
297 start_idx++;
298 start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec,
299 /*exact=*/true, &line_entry);
300 } while (start_idx != UINT32_MAX);
301
302 // Try the next higher line, starting over at start_idx 0.
303 line++;
Dawn Perchik954b40b2016-01-05 19:51:51 +0000304 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000305 }
306 }
307 return num_matches;
308 }
309
310 // Dump the requested line entries for the file in the module.
311 // Return the number of entries found.
312 // If module_list is set, only dump lines contained in one of the modules.
313 // If the start_line option was specified, don't print lines less than
314 // start_line.
315 // If the end_line option was specified, don't print lines greater than
316 // end_line.
317 // If the num_lines option was specified, dont print more than num_lines
318 // entries.
319 uint32_t DumpFileLinesInModule(Stream &strm, Module *module,
320 const FileSpec &file_spec) {
321 uint32_t num_matches = 0;
322 if (module) {
323 // Look through all the compilation units (CUs) in this module for ones
324 // that
325 // contain lines of code from this source file.
326 for (size_t i = 0; i < module->GetNumCompileUnits(); i++) {
327 // Look for a matching source file in this CU.
328 CompUnitSP cu_sp(module->GetCompileUnitAtIndex(i));
329 if (cu_sp) {
330 num_matches +=
331 DumpFileLinesInCompUnit(strm, module, cu_sp.get(), file_spec);
Dawn Perchik954b40b2016-01-05 19:51:51 +0000332 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000333 }
334 }
335 return num_matches;
336 }
337
338 // Given an address and a list of modules, append the symbol contexts of all
339 // line entries
340 // containing the address found in the modules and return the count of
341 // matches. If none
342 // is found, return an error in 'error_strm'.
343 size_t GetSymbolContextsForAddress(const ModuleList &module_list,
344 lldb::addr_t addr,
345 SymbolContextList &sc_list,
346 StreamString &error_strm) {
347 Address so_addr;
348 size_t num_matches = 0;
349 assert(module_list.GetSize() > 0);
350 Target *target = m_exe_ctx.GetTargetPtr();
351 if (target->GetSectionLoadList().IsEmpty()) {
352 // The target isn't loaded yet, we need to lookup the file address in
353 // all modules. Note: the module list option does not apply to addresses.
354 const size_t num_modules = module_list.GetSize();
355 for (size_t i = 0; i < num_modules; ++i) {
356 ModuleSP module_sp(module_list.GetModuleAtIndex(i));
357 if (!module_sp)
358 continue;
359 if (module_sp->ResolveFileAddress(addr, so_addr)) {
360 SymbolContext sc;
361 sc.Clear(true);
362 if (module_sp->ResolveSymbolContextForAddress(
363 so_addr, eSymbolContextEverything, sc) &
364 eSymbolContextLineEntry) {
365 sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false);
366 ++num_matches;
367 }
Dawn Perchik954b40b2016-01-05 19:51:51 +0000368 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000369 }
370 if (num_matches == 0)
371 error_strm.Printf("Source information for file address 0x%" PRIx64
372 " not found in any modules.\n",
373 addr);
374 } else {
375 // The target has some things loaded, resolve this address to a
376 // compile unit + file + line and display
377 if (target->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) {
378 ModuleSP module_sp(so_addr.GetModule());
379 // Check to make sure this module is in our list.
380 if (module_sp &&
381 module_list.GetIndexForModule(module_sp.get()) !=
382 LLDB_INVALID_INDEX32) {
383 SymbolContext sc;
384 sc.Clear(true);
385 if (module_sp->ResolveSymbolContextForAddress(
386 so_addr, eSymbolContextEverything, sc) &
387 eSymbolContextLineEntry) {
388 sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false);
389 ++num_matches;
390 } else {
391 StreamString addr_strm;
392 so_addr.Dump(&addr_strm, nullptr,
393 Address::DumpStyleModuleWithFileAddress);
394 error_strm.Printf(
395 "Address 0x%" PRIx64 " resolves to %s, but there is"
396 " no source information available for this address.\n",
397 addr, addr_strm.GetData());
398 }
399 } else {
400 StreamString addr_strm;
401 so_addr.Dump(&addr_strm, nullptr,
402 Address::DumpStyleModuleWithFileAddress);
403 error_strm.Printf("Address 0x%" PRIx64
404 " resolves to %s, but it cannot"
405 " be found in any modules.\n",
406 addr, addr_strm.GetData());
Dawn Perchik954b40b2016-01-05 19:51:51 +0000407 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000408 } else
409 error_strm.Printf("Unable to resolve address 0x%" PRIx64 ".\n", addr);
410 }
411 return num_matches;
412 }
413
414 // Dump the line entries found in functions matching the name specified in the
415 // option.
416 bool DumpLinesInFunctions(CommandReturnObject &result) {
417 SymbolContextList sc_list_funcs;
418 ConstString name(m_options.symbol_name.c_str());
419 SymbolContextList sc_list_lines;
420 Target *target = m_exe_ctx.GetTargetPtr();
421 uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
422
423 // Note: module_list can't be const& because FindFunctionSymbols isn't
424 // const.
425 ModuleList module_list =
426 (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages();
427 size_t num_matches =
428 module_list.FindFunctions(name, eFunctionNameTypeAuto,
429 /*include_symbols=*/false,
430 /*include_inlines=*/true,
431 /*append=*/true, sc_list_funcs);
432 if (!num_matches) {
433 // If we didn't find any functions with that name, try searching for
434 // symbols that line up exactly with function addresses.
435 SymbolContextList sc_list_symbols;
436 size_t num_symbol_matches = module_list.FindFunctionSymbols(
437 name, eFunctionNameTypeAuto, sc_list_symbols);
438 for (size_t i = 0; i < num_symbol_matches; i++) {
439 SymbolContext sc;
440 sc_list_symbols.GetContextAtIndex(i, sc);
441 if (sc.symbol && sc.symbol->ValueIsAddress()) {
442 const Address &base_address = sc.symbol->GetAddressRef();
443 Function *function = base_address.CalculateSymbolContextFunction();
444 if (function) {
445 sc_list_funcs.Append(SymbolContext(function));
446 num_matches++;
447 }
Dawn Perchik954b40b2016-01-05 19:51:51 +0000448 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000449 }
450 }
451 if (num_matches == 0) {
452 result.AppendErrorWithFormat("Could not find function named \'%s\'.\n",
453 m_options.symbol_name.c_str());
454 return false;
455 }
456 for (size_t i = 0; i < num_matches; i++) {
457 SymbolContext sc;
458 sc_list_funcs.GetContextAtIndex(i, sc);
459 bool context_found_for_symbol = false;
460 // Loop through all the ranges in the function.
461 AddressRange range;
462 for (uint32_t r = 0;
463 sc.GetAddressRange(eSymbolContextEverything, r,
464 /*use_inline_block_range=*/true, range);
465 ++r) {
466 // Append the symbol contexts for each address in the range to
467 // sc_list_lines.
468 const Address &base_address = range.GetBaseAddress();
469 const addr_t size = range.GetByteSize();
470 lldb::addr_t start_addr = base_address.GetLoadAddress(target);
471 if (start_addr == LLDB_INVALID_ADDRESS)
472 start_addr = base_address.GetFileAddress();
473 lldb::addr_t end_addr = start_addr + size;
474 for (lldb::addr_t addr = start_addr; addr < end_addr;
475 addr += addr_byte_size) {
476 StreamString error_strm;
477 if (!GetSymbolContextsForAddress(module_list, addr, sc_list_lines,
478 error_strm))
479 result.AppendWarningWithFormat("in symbol '%s': %s",
480 sc.GetFunctionName().AsCString(),
481 error_strm.GetData());
482 else
483 context_found_for_symbol = true;
484 }
485 }
486 if (!context_found_for_symbol)
487 result.AppendWarningWithFormat("Unable to find line information"
488 " for matching symbol '%s'.\n",
489 sc.GetFunctionName().AsCString());
490 }
491 if (sc_list_lines.GetSize() == 0) {
492 result.AppendErrorWithFormat("No line information could be found"
493 " for any symbols matching '%s'.\n",
494 name.AsCString());
495 return false;
496 }
497 FileSpec file_spec;
498 if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list_lines,
499 module_list, file_spec)) {
500 result.AppendErrorWithFormat(
501 "Unable to dump line information for symbol '%s'.\n",
502 name.AsCString());
503 return false;
504 }
505 return true;
506 }
507
508 // Dump the line entries found for the address specified in the option.
509 bool DumpLinesForAddress(CommandReturnObject &result) {
510 Target *target = m_exe_ctx.GetTargetPtr();
511 SymbolContextList sc_list;
512
513 StreamString error_strm;
514 if (!GetSymbolContextsForAddress(target->GetImages(), m_options.address,
515 sc_list, error_strm)) {
516 result.AppendErrorWithFormat("%s.\n", error_strm.GetData());
517 return false;
518 }
519 ModuleList module_list;
520 FileSpec file_spec;
521 if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list,
522 module_list, file_spec)) {
523 result.AppendErrorWithFormat("No modules contain load address 0x%" PRIx64
524 ".\n",
525 m_options.address);
526 return false;
527 }
528 return true;
529 }
530
531 // Dump the line entries found in the file specified in the option.
532 bool DumpLinesForFile(CommandReturnObject &result) {
533 FileSpec file_spec(m_options.file_name, false);
534 const char *filename = m_options.file_name.c_str();
535 Target *target = m_exe_ctx.GetTargetPtr();
536 const ModuleList &module_list =
537 (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages();
538
539 bool displayed_something = false;
540 const size_t num_modules = module_list.GetSize();
541 for (uint32_t i = 0; i < num_modules; ++i) {
542 // Dump lines for this module.
543 Module *module = module_list.GetModulePointerAtIndex(i);
544 assert(module);
545 if (DumpFileLinesInModule(result.GetOutputStream(), module, file_spec))
546 displayed_something = true;
547 }
548 if (!displayed_something) {
549 result.AppendErrorWithFormat("No source filenames matched '%s'.\n",
550 filename);
551 return false;
552 }
553 return true;
554 }
555
556 // Dump the line entries for the current frame.
557 bool DumpLinesForFrame(CommandReturnObject &result) {
558 StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
559 if (cur_frame == nullptr) {
560 result.AppendError(
561 "No selected frame to use to find the default source.");
562 return false;
563 } else if (!cur_frame->HasDebugInformation()) {
564 result.AppendError("No debug info for the selected frame.");
565 return false;
566 } else {
567 const SymbolContext &sc =
568 cur_frame->GetSymbolContext(eSymbolContextLineEntry);
569 SymbolContextList sc_list;
570 sc_list.Append(sc);
571 ModuleList module_list;
572 FileSpec file_spec;
573 if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list,
574 module_list, file_spec)) {
575 result.AppendError(
576 "No source line info available for the selected frame.");
577 return false;
578 }
579 }
580 return true;
581 }
582
583 bool DoExecute(Args &command, CommandReturnObject &result) override {
584 const size_t argc = command.GetArgumentCount();
585
586 if (argc != 0) {
587 result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n",
588 GetCommandName());
589 result.SetStatus(eReturnStatusFailed);
590 return false;
Dawn Perchik954b40b2016-01-05 19:51:51 +0000591 }
592
Kate Stoneb9c1b512016-09-06 20:57:50 +0000593 Target *target = m_exe_ctx.GetTargetPtr();
594 if (target == nullptr) {
595 target = m_interpreter.GetDebugger().GetSelectedTarget().get();
596 if (target == nullptr) {
597 result.AppendError("invalid target, create a debug target using the "
598 "'target create' command.");
599 result.SetStatus(eReturnStatusFailed);
600 return false;
601 }
Dawn Perchik954b40b2016-01-05 19:51:51 +0000602 }
603
Kate Stoneb9c1b512016-09-06 20:57:50 +0000604 uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
605 result.GetOutputStream().SetAddressByteSize(addr_byte_size);
606 result.GetErrorStream().SetAddressByteSize(addr_byte_size);
Dawn Perchik954b40b2016-01-05 19:51:51 +0000607
Kate Stoneb9c1b512016-09-06 20:57:50 +0000608 // Collect the list of modules to search.
609 m_module_list.Clear();
610 if (!m_options.modules.empty()) {
611 for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) {
612 FileSpec module_file_spec(m_options.modules[i].c_str(), false);
613 if (module_file_spec) {
614 ModuleSpec module_spec(module_file_spec);
615 if (target->GetImages().FindModules(module_spec, m_module_list) == 0)
616 result.AppendWarningWithFormat("No module found for '%s'.\n",
617 m_options.modules[i].c_str());
Dawn Perchik954b40b2016-01-05 19:51:51 +0000618 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000619 }
620 if (!m_module_list.GetSize()) {
621 result.AppendError("No modules match the input.");
622 result.SetStatus(eReturnStatusFailed);
623 return false;
624 }
625 } else if (target->GetImages().GetSize() == 0) {
626 result.AppendError("The target has no associated executable images.");
627 result.SetStatus(eReturnStatusFailed);
628 return false;
Dawn Perchik954b40b2016-01-05 19:51:51 +0000629 }
630
Kate Stoneb9c1b512016-09-06 20:57:50 +0000631 // Check the arguments to see what lines we should dump.
632 if (!m_options.symbol_name.empty()) {
633 // Print lines for symbol.
634 if (DumpLinesInFunctions(result))
635 result.SetStatus(eReturnStatusSuccessFinishResult);
636 else
637 result.SetStatus(eReturnStatusFailed);
638 } else if (m_options.address != LLDB_INVALID_ADDRESS) {
639 // Print lines for an address.
640 if (DumpLinesForAddress(result))
641 result.SetStatus(eReturnStatusSuccessFinishResult);
642 else
643 result.SetStatus(eReturnStatusFailed);
644 } else if (!m_options.file_name.empty()) {
645 // Dump lines for a file.
646 if (DumpLinesForFile(result))
647 result.SetStatus(eReturnStatusSuccessFinishResult);
648 else
649 result.SetStatus(eReturnStatusFailed);
650 } else {
651 // Dump the line for the current frame.
652 if (DumpLinesForFrame(result))
653 result.SetStatus(eReturnStatusSuccessFinishResult);
654 else
655 result.SetStatus(eReturnStatusFailed);
Dawn Perchik954b40b2016-01-05 19:51:51 +0000656 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000657 return result.Succeeded();
658 }
Dawn Perchik954b40b2016-01-05 19:51:51 +0000659
Kate Stoneb9c1b512016-09-06 20:57:50 +0000660 CommandOptions m_options;
661 ModuleList m_module_list;
Jim Inghamebc09c32010-07-07 03:36:20 +0000662};
663
Jim Inghamebc09c32010-07-07 03:36:20 +0000664#pragma mark CommandObjectSourceList
665//-------------------------------------------------------------------------
666// CommandObjectSourceList
667//-------------------------------------------------------------------------
668
Zachary Turner1f0f5b52016-09-22 20:22:55 +0000669static OptionDefinition g_source_list_options[] = {
670 // clang-format off
671 { LLDB_OPT_SET_ALL, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "The number of source lines to display." },
672 { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "shlib", 's', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Look up the source file in the given shared library." },
673 { LLDB_OPT_SET_ALL, false, "show-breakpoints", 'b', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Show the line table locations from the debug information that indicate valid places to set source level breakpoints." },
674 { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source." },
675 { LLDB_OPT_SET_1, false, "line", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLineNum, "The line number at which to start the display source." },
676 { LLDB_OPT_SET_2, false, "name", 'n', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSymbolCompletion, eArgTypeSymbol, "The name of a function whose source to display." },
677 { LLDB_OPT_SET_3, false, "address", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddressOrExpression, "Lookup the address and display the source information for the corresponding file and line." },
678 { LLDB_OPT_SET_4, false, "reverse", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Reverse the listing to look backwards from the last displayed block of source." },
679 // clang-format on
680};
681
Kate Stoneb9c1b512016-09-06 20:57:50 +0000682class CommandObjectSourceList : public CommandObjectParsed {
683 class CommandOptions : public Options {
684 public:
685 CommandOptions() : Options() {}
Jim Inghamebc09c32010-07-07 03:36:20 +0000686
Kate Stoneb9c1b512016-09-06 20:57:50 +0000687 ~CommandOptions() override = default;
Jim Inghamebc09c32010-07-07 03:36:20 +0000688
Kate Stoneb9c1b512016-09-06 20:57:50 +0000689 Error SetOptionValue(uint32_t option_idx, const char *option_arg,
690 ExecutionContext *execution_context) override {
691 Error error;
Zachary Turner1f0f5b52016-09-22 20:22:55 +0000692 const int short_option = GetDefinitions()[option_idx].short_option;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000693 switch (short_option) {
694 case 'l':
695 start_line = StringConvert::ToUInt32(option_arg, 0);
696 if (start_line == 0)
697 error.SetErrorStringWithFormat("invalid line number: '%s'",
698 option_arg);
699 break;
Jim Inghamebc09c32010-07-07 03:36:20 +0000700
Kate Stoneb9c1b512016-09-06 20:57:50 +0000701 case 'c':
702 num_lines = StringConvert::ToUInt32(option_arg, 0);
703 if (num_lines == 0)
704 error.SetErrorStringWithFormat("invalid line count: '%s'",
705 option_arg);
706 break;
Jim Inghamebc09c32010-07-07 03:36:20 +0000707
Kate Stoneb9c1b512016-09-06 20:57:50 +0000708 case 'f':
709 file_name = option_arg;
710 break;
Jim Inghamebc09c32010-07-07 03:36:20 +0000711
Kate Stoneb9c1b512016-09-06 20:57:50 +0000712 case 'n':
713 symbol_name = option_arg;
714 break;
Jim Inghamebc09c32010-07-07 03:36:20 +0000715
Kate Stoneb9c1b512016-09-06 20:57:50 +0000716 case 'a': {
717 address = Args::StringToAddress(execution_context, option_arg,
718 LLDB_INVALID_ADDRESS, &error);
719 } break;
720 case 's':
721 modules.push_back(std::string(option_arg));
722 break;
Jim Inghamebc09c32010-07-07 03:36:20 +0000723
Kate Stoneb9c1b512016-09-06 20:57:50 +0000724 case 'b':
725 show_bp_locs = true;
726 break;
727 case 'r':
728 reverse = true;
729 break;
730 default:
731 error.SetErrorStringWithFormat("unrecognized short option '%c'",
732 short_option);
733 break;
734 }
Jim Inghamebc09c32010-07-07 03:36:20 +0000735
Kate Stoneb9c1b512016-09-06 20:57:50 +0000736 return error;
737 }
Eugene Zelenko3f18ea02016-02-24 02:05:55 +0000738
Kate Stoneb9c1b512016-09-06 20:57:50 +0000739 void OptionParsingStarting(ExecutionContext *execution_context) override {
740 file_spec.Clear();
741 file_name.clear();
742 symbol_name.clear();
743 address = LLDB_INVALID_ADDRESS;
744 start_line = 0;
745 num_lines = 0;
746 show_bp_locs = false;
747 reverse = false;
748 modules.clear();
749 }
Jim Inghamebc09c32010-07-07 03:36:20 +0000750
Zachary Turner1f0f5b52016-09-22 20:22:55 +0000751 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
752 return g_source_list_options;
753 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000754
755 // Instance variables to hold the values for command options.
756 FileSpec file_spec;
757 std::string file_name;
758 std::string symbol_name;
759 lldb::addr_t address;
760 uint32_t start_line;
761 uint32_t num_lines;
762 STLStringArray modules;
763 bool show_bp_locs;
764 bool reverse;
765 };
Kate Stone7428a182016-07-14 22:03:10 +0000766
767public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000768 CommandObjectSourceList(CommandInterpreter &interpreter)
769 : CommandObjectParsed(interpreter, "source list",
770 "Display source code for the current target "
771 "process as specified by options.",
772 nullptr, eCommandRequiresTarget),
773 m_options() {}
Jim Inghamebc09c32010-07-07 03:36:20 +0000774
Kate Stoneb9c1b512016-09-06 20:57:50 +0000775 ~CommandObjectSourceList() override = default;
Jim Inghamebc09c32010-07-07 03:36:20 +0000776
Kate Stoneb9c1b512016-09-06 20:57:50 +0000777 Options *GetOptions() override { return &m_options; }
Jim Inghamebc09c32010-07-07 03:36:20 +0000778
Kate Stoneb9c1b512016-09-06 20:57:50 +0000779 const char *GetRepeatCommand(Args &current_command_args,
780 uint32_t index) override {
781 // This is kind of gross, but the command hasn't been parsed yet so we can't
782 // look at the option
783 // values for this invocation... I have to scan the arguments directly.
784 size_t num_args = current_command_args.GetArgumentCount();
785 bool is_reverse = false;
786 for (size_t i = 0; i < num_args; i++) {
787 const char *arg = current_command_args.GetArgumentAtIndex(i);
788 if (arg && (strcmp(arg, "-r") == 0 || strcmp(arg, "--reverse") == 0)) {
789 is_reverse = true;
790 }
Jim Ingham5a988412012-06-08 21:56:10 +0000791 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000792 if (is_reverse) {
793 if (m_reverse_name.empty()) {
794 m_reverse_name = m_cmd_name;
795 m_reverse_name.append(" -r");
796 }
797 return m_reverse_name.c_str();
798 } else
799 return m_cmd_name.c_str();
800 }
Jim Ingham5a988412012-06-08 21:56:10 +0000801
802protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000803 struct SourceInfo {
804 ConstString function;
805 LineEntry line_entry;
Greg Claytonef2129d2013-05-17 00:56:10 +0000806
Kate Stoneb9c1b512016-09-06 20:57:50 +0000807 SourceInfo(const ConstString &name, const LineEntry &line_entry)
808 : function(name), line_entry(line_entry) {}
Greg Claytonef2129d2013-05-17 00:56:10 +0000809
Kate Stoneb9c1b512016-09-06 20:57:50 +0000810 SourceInfo() : function(), line_entry() {}
Greg Claytonef2129d2013-05-17 00:56:10 +0000811
Kate Stoneb9c1b512016-09-06 20:57:50 +0000812 bool IsValid() const { return (bool)function && line_entry.IsValid(); }
Greg Claytonef2129d2013-05-17 00:56:10 +0000813
Kate Stoneb9c1b512016-09-06 20:57:50 +0000814 bool operator==(const SourceInfo &rhs) const {
815 return function == rhs.function &&
816 line_entry.original_file == rhs.line_entry.original_file &&
817 line_entry.line == rhs.line_entry.line;
Greg Claytonef2129d2013-05-17 00:56:10 +0000818 }
819
Kate Stoneb9c1b512016-09-06 20:57:50 +0000820 bool operator!=(const SourceInfo &rhs) const {
821 return function != rhs.function ||
822 line_entry.original_file != rhs.line_entry.original_file ||
823 line_entry.line != rhs.line_entry.line;
824 }
825
826 bool operator<(const SourceInfo &rhs) const {
827 if (function.GetCString() < rhs.function.GetCString())
828 return true;
829 if (line_entry.file.GetDirectory().GetCString() <
830 rhs.line_entry.file.GetDirectory().GetCString())
831 return true;
832 if (line_entry.file.GetFilename().GetCString() <
833 rhs.line_entry.file.GetFilename().GetCString())
834 return true;
835 if (line_entry.line < rhs.line_entry.line)
836 return true;
837 return false;
838 }
839 };
840
841 size_t DisplayFunctionSource(const SymbolContext &sc, SourceInfo &source_info,
842 CommandReturnObject &result) {
843 if (!source_info.IsValid()) {
844 source_info.function = sc.GetFunctionName();
845 source_info.line_entry = sc.GetFunctionStartLineEntry();
846 }
847
848 if (sc.function) {
849 Target *target = m_exe_ctx.GetTargetPtr();
850
851 FileSpec start_file;
852 uint32_t start_line;
853 uint32_t end_line;
854 FileSpec end_file;
855
856 if (sc.block == nullptr) {
857 // Not an inlined function
858 sc.function->GetStartLineSourceInfo(start_file, start_line);
859 if (start_line == 0) {
860 result.AppendErrorWithFormat("Could not find line information for "
861 "start of function: \"%s\".\n",
862 source_info.function.GetCString());
863 result.SetStatus(eReturnStatusFailed);
864 return 0;
865 }
866 sc.function->GetEndLineSourceInfo(end_file, end_line);
867 } else {
868 // We have an inlined function
869 start_file = source_info.line_entry.file;
870 start_line = source_info.line_entry.line;
871 end_line = start_line + m_options.num_lines;
872 }
873
874 // This is a little hacky, but the first line table entry for a function
875 // points to the "{" that
876 // starts the function block. It would be nice to actually get the
877 // function
878 // declaration in there too. So back up a bit, but not further than what
879 // you're going to display.
880 uint32_t extra_lines;
881 if (m_options.num_lines >= 10)
882 extra_lines = 5;
883 else
884 extra_lines = m_options.num_lines / 2;
885 uint32_t line_no;
886 if (start_line <= extra_lines)
887 line_no = 1;
888 else
889 line_no = start_line - extra_lines;
890
891 // For fun, if the function is shorter than the number of lines we're
892 // supposed to display,
893 // only display the function...
894 if (end_line != 0) {
895 if (m_options.num_lines > end_line - line_no)
896 m_options.num_lines = end_line - line_no + extra_lines;
897 }
898
899 m_breakpoint_locations.Clear();
900
901 if (m_options.show_bp_locs) {
902 const bool show_inlines = true;
903 m_breakpoint_locations.Reset(start_file, 0, show_inlines);
904 SearchFilterForUnconstrainedSearches target_search_filter(
905 m_exe_ctx.GetTargetSP());
906 target_search_filter.Search(m_breakpoint_locations);
907 }
908
909 result.AppendMessageWithFormat("File: %s\n",
910 start_file.GetPath().c_str());
Todd Fiala9666ba72016-09-21 20:13:14 +0000911 // We don't care about the column here.
912 const uint32_t column = 0;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000913 return target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
Todd Fiala9666ba72016-09-21 20:13:14 +0000914 start_file, line_no, 0, m_options.num_lines, column, "",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000915 &result.GetOutputStream(), GetBreakpointLocations());
916 } else {
917 result.AppendErrorWithFormat(
918 "Could not find function info for: \"%s\".\n",
919 m_options.symbol_name.c_str());
920 }
921 return 0;
922 }
923
924 // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols functions
925 // "take a possibly empty vector of strings which are names of modules, and
926 // run the two search functions on the subset of the full module list that
927 // matches the strings in the input vector". If we wanted to put these
928 // somewhere,
929 // there should probably be a module-filter-list that can be passed to the
930 // various ModuleList::Find* calls, which would either be a vector of string
931 // names or a ModuleSpecList.
932 size_t FindMatchingFunctions(Target *target, const ConstString &name,
933 SymbolContextList &sc_list) {
934 // Displaying the source for a symbol:
935 bool include_inlines = true;
936 bool append = true;
937 bool include_symbols = false;
938 size_t num_matches = 0;
939
940 if (m_options.num_lines == 0)
941 m_options.num_lines = 10;
942
943 const size_t num_modules = m_options.modules.size();
944 if (num_modules > 0) {
945 ModuleList matching_modules;
946 for (size_t i = 0; i < num_modules; ++i) {
947 FileSpec module_file_spec(m_options.modules[i].c_str(), false);
948 if (module_file_spec) {
949 ModuleSpec module_spec(module_file_spec);
950 matching_modules.Clear();
951 target->GetImages().FindModules(module_spec, matching_modules);
952 num_matches += matching_modules.FindFunctions(
953 name, eFunctionNameTypeAuto, include_symbols, include_inlines,
954 append, sc_list);
955 }
956 }
957 } else {
958 num_matches = target->GetImages().FindFunctions(
959 name, eFunctionNameTypeAuto, include_symbols, include_inlines, append,
960 sc_list);
961 }
962 return num_matches;
963 }
964
965 size_t FindMatchingFunctionSymbols(Target *target, const ConstString &name,
966 SymbolContextList &sc_list) {
967 size_t num_matches = 0;
968 const size_t num_modules = m_options.modules.size();
969 if (num_modules > 0) {
970 ModuleList matching_modules;
971 for (size_t i = 0; i < num_modules; ++i) {
972 FileSpec module_file_spec(m_options.modules[i].c_str(), false);
973 if (module_file_spec) {
974 ModuleSpec module_spec(module_file_spec);
975 matching_modules.Clear();
976 target->GetImages().FindModules(module_spec, matching_modules);
977 num_matches += matching_modules.FindFunctionSymbols(
978 name, eFunctionNameTypeAuto, sc_list);
979 }
980 }
981 } else {
982 num_matches = target->GetImages().FindFunctionSymbols(
983 name, eFunctionNameTypeAuto, sc_list);
984 }
985 return num_matches;
986 }
987
988 bool DoExecute(Args &command, CommandReturnObject &result) override {
989 const size_t argc = command.GetArgumentCount();
990
991 if (argc != 0) {
992 result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n",
993 GetCommandName());
994 result.SetStatus(eReturnStatusFailed);
995 return false;
996 }
997
998 Target *target = m_exe_ctx.GetTargetPtr();
999
1000 if (!m_options.symbol_name.empty()) {
1001 SymbolContextList sc_list;
1002 ConstString name(m_options.symbol_name.c_str());
1003
1004 // Displaying the source for a symbol. Search for function named name.
1005 size_t num_matches = FindMatchingFunctions(target, name, sc_list);
1006 if (!num_matches) {
1007 // If we didn't find any functions with that name, try searching for
1008 // symbols
1009 // that line up exactly with function addresses.
1010 SymbolContextList sc_list_symbols;
1011 size_t num_symbol_matches =
1012 FindMatchingFunctionSymbols(target, name, sc_list_symbols);
1013 for (size_t i = 0; i < num_symbol_matches; i++) {
1014 SymbolContext sc;
1015 sc_list_symbols.GetContextAtIndex(i, sc);
1016 if (sc.symbol && sc.symbol->ValueIsAddress()) {
1017 const Address &base_address = sc.symbol->GetAddressRef();
1018 Function *function = base_address.CalculateSymbolContextFunction();
1019 if (function) {
1020 sc_list.Append(SymbolContext(function));
1021 num_matches++;
1022 break;
1023 }
1024 }
1025 }
1026 }
1027
1028 if (num_matches == 0) {
1029 result.AppendErrorWithFormat("Could not find function named: \"%s\".\n",
1030 m_options.symbol_name.c_str());
1031 result.SetStatus(eReturnStatusFailed);
1032 return false;
1033 }
1034
1035 if (num_matches > 1) {
1036 std::set<SourceInfo> source_match_set;
1037
1038 bool displayed_something = false;
1039 for (size_t i = 0; i < num_matches; i++) {
1040 SymbolContext sc;
1041 sc_list.GetContextAtIndex(i, sc);
1042 SourceInfo source_info(sc.GetFunctionName(),
1043 sc.GetFunctionStartLineEntry());
1044
1045 if (source_info.IsValid()) {
1046 if (source_match_set.find(source_info) == source_match_set.end()) {
1047 source_match_set.insert(source_info);
1048 if (DisplayFunctionSource(sc, source_info, result))
1049 displayed_something = true;
1050 }
1051 }
1052 }
1053
1054 if (displayed_something)
1055 result.SetStatus(eReturnStatusSuccessFinishResult);
1056 else
1057 result.SetStatus(eReturnStatusFailed);
1058 } else {
1059 SymbolContext sc;
1060 sc_list.GetContextAtIndex(0, sc);
1061 SourceInfo source_info;
1062
1063 if (DisplayFunctionSource(sc, source_info, result)) {
1064 result.SetStatus(eReturnStatusSuccessFinishResult);
1065 } else {
1066 result.SetStatus(eReturnStatusFailed);
1067 }
1068 }
1069 return result.Succeeded();
1070 } else if (m_options.address != LLDB_INVALID_ADDRESS) {
1071 Address so_addr;
1072 StreamString error_strm;
1073 SymbolContextList sc_list;
1074
1075 if (target->GetSectionLoadList().IsEmpty()) {
1076 // The target isn't loaded yet, we need to lookup the file address
1077 // in all modules
1078 const ModuleList &module_list = target->GetImages();
1079 const size_t num_modules = module_list.GetSize();
1080 for (size_t i = 0; i < num_modules; ++i) {
1081 ModuleSP module_sp(module_list.GetModuleAtIndex(i));
1082 if (module_sp &&
1083 module_sp->ResolveFileAddress(m_options.address, so_addr)) {
1084 SymbolContext sc;
1085 sc.Clear(true);
1086 if (module_sp->ResolveSymbolContextForAddress(
1087 so_addr, eSymbolContextEverything, sc) &
1088 eSymbolContextLineEntry)
1089 sc_list.Append(sc);
1090 }
1091 }
1092
1093 if (sc_list.GetSize() == 0) {
1094 result.AppendErrorWithFormat(
1095 "no modules have source information for file address 0x%" PRIx64
1096 ".\n",
1097 m_options.address);
1098 result.SetStatus(eReturnStatusFailed);
1099 return false;
1100 }
1101 } else {
1102 // The target has some things loaded, resolve this address to a
1103 // compile unit + file + line and display
1104 if (target->GetSectionLoadList().ResolveLoadAddress(m_options.address,
1105 so_addr)) {
1106 ModuleSP module_sp(so_addr.GetModule());
1107 if (module_sp) {
1108 SymbolContext sc;
1109 sc.Clear(true);
1110 if (module_sp->ResolveSymbolContextForAddress(
1111 so_addr, eSymbolContextEverything, sc) &
1112 eSymbolContextLineEntry) {
1113 sc_list.Append(sc);
1114 } else {
1115 so_addr.Dump(&error_strm, nullptr,
1116 Address::DumpStyleModuleWithFileAddress);
1117 result.AppendErrorWithFormat("address resolves to %s, but there "
1118 "is no line table information "
1119 "available for this address.\n",
1120 error_strm.GetData());
1121 result.SetStatus(eReturnStatusFailed);
1122 return false;
1123 }
1124 }
1125 }
1126
1127 if (sc_list.GetSize() == 0) {
1128 result.AppendErrorWithFormat(
1129 "no modules contain load address 0x%" PRIx64 ".\n",
1130 m_options.address);
1131 result.SetStatus(eReturnStatusFailed);
1132 return false;
1133 }
1134 }
1135 uint32_t num_matches = sc_list.GetSize();
1136 for (uint32_t i = 0; i < num_matches; ++i) {
1137 SymbolContext sc;
1138 sc_list.GetContextAtIndex(i, sc);
1139 if (sc.comp_unit) {
1140 if (m_options.show_bp_locs) {
1141 m_breakpoint_locations.Clear();
1142 const bool show_inlines = true;
1143 m_breakpoint_locations.Reset(*sc.comp_unit, 0, show_inlines);
1144 SearchFilterForUnconstrainedSearches target_search_filter(
1145 target->shared_from_this());
1146 target_search_filter.Search(m_breakpoint_locations);
1147 }
1148
1149 bool show_fullpaths = true;
1150 bool show_module = true;
1151 bool show_inlined_frames = true;
1152 const bool show_function_arguments = true;
1153 const bool show_function_name = true;
1154 sc.DumpStopContext(&result.GetOutputStream(),
1155 m_exe_ctx.GetBestExecutionContextScope(),
1156 sc.line_entry.range.GetBaseAddress(),
1157 show_fullpaths, show_module, show_inlined_frames,
1158 show_function_arguments, show_function_name);
1159 result.GetOutputStream().EOL();
1160
1161 if (m_options.num_lines == 0)
Michael Sartaincc791bb2013-07-11 16:40:56 +00001162 m_options.num_lines = 10;
1163
Kate Stoneb9c1b512016-09-06 20:57:50 +00001164 size_t lines_to_back_up =
1165 m_options.num_lines >= 10 ? 5 : m_options.num_lines / 2;
1166
Todd Fiala9666ba72016-09-21 20:13:14 +00001167 const uint32_t column =
1168 (m_interpreter.GetDebugger().GetStopShowColumn() !=
1169 eStopShowColumnNone)
1170 ? sc.line_entry.column
1171 : 0;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001172 target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
Todd Fiala9666ba72016-09-21 20:13:14 +00001173 sc.comp_unit, sc.line_entry.line, lines_to_back_up, column,
Kate Stoneb9c1b512016-09-06 20:57:50 +00001174 m_options.num_lines - lines_to_back_up, "->",
1175 &result.GetOutputStream(), GetBreakpointLocations());
1176 result.SetStatus(eReturnStatusSuccessFinishResult);
Michael Sartaincc791bb2013-07-11 16:40:56 +00001177 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001178 }
1179 } else if (m_options.file_name.empty()) {
1180 // Last valid source manager context, or the current frame if no
1181 // valid last context in source manager.
1182 // One little trick here, if you type the exact same list command twice in
1183 // a row, it is
1184 // more likely because you typed it once, then typed it again
1185 if (m_options.start_line == 0) {
1186 if (target->GetSourceManager().DisplayMoreWithLineNumbers(
1187 &result.GetOutputStream(), m_options.num_lines,
1188 m_options.reverse, GetBreakpointLocations())) {
1189 result.SetStatus(eReturnStatusSuccessFinishResult);
Michael Sartaincc791bb2013-07-11 16:40:56 +00001190 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001191 } else {
1192 if (m_options.num_lines == 0)
1193 m_options.num_lines = 10;
1194
1195 if (m_options.show_bp_locs) {
1196 SourceManager::FileSP last_file_sp(
1197 target->GetSourceManager().GetLastFile());
1198 if (last_file_sp) {
1199 const bool show_inlines = true;
1200 m_breakpoint_locations.Reset(last_file_sp->GetFileSpec(), 0,
1201 show_inlines);
1202 SearchFilterForUnconstrainedSearches target_search_filter(
1203 target->shared_from_this());
1204 target_search_filter.Search(m_breakpoint_locations);
1205 }
1206 } else
1207 m_breakpoint_locations.Clear();
1208
Todd Fiala9666ba72016-09-21 20:13:14 +00001209 const uint32_t column = 0;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001210 if (target->GetSourceManager()
1211 .DisplaySourceLinesWithLineNumbersUsingLastFile(
1212 m_options.start_line, // Line to display
1213 m_options.num_lines, // Lines after line to
1214 UINT32_MAX, // Don't mark "line"
Todd Fiala9666ba72016-09-21 20:13:14 +00001215 column,
1216 "", // Don't mark "line"
Kate Stoneb9c1b512016-09-06 20:57:50 +00001217 &result.GetOutputStream(), GetBreakpointLocations())) {
1218 result.SetStatus(eReturnStatusSuccessFinishResult);
1219 }
1220 }
1221 } else {
1222 const char *filename = m_options.file_name.c_str();
1223
1224 bool check_inlines = false;
1225 SymbolContextList sc_list;
1226 size_t num_matches = 0;
1227
1228 if (!m_options.modules.empty()) {
1229 ModuleList matching_modules;
1230 for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) {
1231 FileSpec module_file_spec(m_options.modules[i].c_str(), false);
1232 if (module_file_spec) {
1233 ModuleSpec module_spec(module_file_spec);
1234 matching_modules.Clear();
1235 target->GetImages().FindModules(module_spec, matching_modules);
1236 num_matches += matching_modules.ResolveSymbolContextForFilePath(
1237 filename, 0, check_inlines,
1238 eSymbolContextModule | eSymbolContextCompUnit, sc_list);
1239 }
1240 }
1241 } else {
1242 num_matches = target->GetImages().ResolveSymbolContextForFilePath(
1243 filename, 0, check_inlines,
1244 eSymbolContextModule | eSymbolContextCompUnit, sc_list);
1245 }
1246
1247 if (num_matches == 0) {
1248 result.AppendErrorWithFormat("Could not find source file \"%s\".\n",
1249 m_options.file_name.c_str());
1250 result.SetStatus(eReturnStatusFailed);
1251 return false;
1252 }
1253
1254 if (num_matches > 1) {
1255 bool got_multiple = false;
1256 FileSpec *test_cu_spec = nullptr;
1257
1258 for (unsigned i = 0; i < num_matches; i++) {
1259 SymbolContext sc;
1260 sc_list.GetContextAtIndex(i, sc);
1261 if (sc.comp_unit) {
1262 if (test_cu_spec) {
1263 if (test_cu_spec != static_cast<FileSpec *>(sc.comp_unit))
1264 got_multiple = true;
1265 break;
1266 } else
1267 test_cu_spec = sc.comp_unit;
1268 }
1269 }
1270 if (got_multiple) {
1271 result.AppendErrorWithFormat(
1272 "Multiple source files found matching: \"%s.\"\n",
1273 m_options.file_name.c_str());
1274 result.SetStatus(eReturnStatusFailed);
1275 return false;
1276 }
1277 }
1278
1279 SymbolContext sc;
1280 if (sc_list.GetContextAtIndex(0, sc)) {
1281 if (sc.comp_unit) {
1282 if (m_options.show_bp_locs) {
1283 const bool show_inlines = true;
1284 m_breakpoint_locations.Reset(*sc.comp_unit, 0, show_inlines);
1285 SearchFilterForUnconstrainedSearches target_search_filter(
1286 target->shared_from_this());
1287 target_search_filter.Search(m_breakpoint_locations);
1288 } else
1289 m_breakpoint_locations.Clear();
1290
1291 if (m_options.num_lines == 0)
1292 m_options.num_lines = 10;
Todd Fiala9666ba72016-09-21 20:13:14 +00001293 const uint32_t column = 0;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001294 target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
Todd Fiala9666ba72016-09-21 20:13:14 +00001295 sc.comp_unit, m_options.start_line, 0, m_options.num_lines,
1296 column, "", &result.GetOutputStream(), GetBreakpointLocations());
Kate Stoneb9c1b512016-09-06 20:57:50 +00001297
1298 result.SetStatus(eReturnStatusSuccessFinishResult);
1299 } else {
1300 result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n",
1301 m_options.file_name.c_str());
1302 result.SetStatus(eReturnStatusFailed);
1303 return false;
1304 }
1305 }
Michael Sartaincc791bb2013-07-11 16:40:56 +00001306 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001307 return result.Succeeded();
1308 }
Michael Sartaincc791bb2013-07-11 16:40:56 +00001309
Kate Stoneb9c1b512016-09-06 20:57:50 +00001310 const SymbolContextList *GetBreakpointLocations() {
1311 if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0)
1312 return &m_breakpoint_locations.GetFileLineMatches();
1313 return nullptr;
1314 }
Michael Sartaincc791bb2013-07-11 16:40:56 +00001315
Kate Stoneb9c1b512016-09-06 20:57:50 +00001316 CommandOptions m_options;
1317 FileLineResolver m_breakpoint_locations;
1318 std::string m_reverse_name;
Jim Inghamebc09c32010-07-07 03:36:20 +00001319};
1320
Jim Inghamebc09c32010-07-07 03:36:20 +00001321#pragma mark CommandObjectMultiwordSource
Jim Inghamebc09c32010-07-07 03:36:20 +00001322//-------------------------------------------------------------------------
1323// CommandObjectMultiwordSource
1324//-------------------------------------------------------------------------
1325
Kate Stoneb9c1b512016-09-06 20:57:50 +00001326CommandObjectMultiwordSource::CommandObjectMultiwordSource(
1327 CommandInterpreter &interpreter)
1328 : CommandObjectMultiword(interpreter, "source", "Commands for examining "
1329 "source code described by "
1330 "debug information for the "
1331 "current target process.",
1332 "source <subcommand> [<subcommand-options>]") {
1333 LoadSubCommand("info",
1334 CommandObjectSP(new CommandObjectSourceInfo(interpreter)));
1335 LoadSubCommand("list",
1336 CommandObjectSP(new CommandObjectSourceList(interpreter)));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001337}
Jim Inghamebc09c32010-07-07 03:36:20 +00001338
Eugene Zelenko3f18ea02016-02-24 02:05:55 +00001339CommandObjectMultiwordSource::~CommandObjectMultiwordSource() = default;