1 //===-- CommandObjectSource.cpp ---------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "CommandObjectSource.h"
11 #include "lldb/Core/Debugger.h"
12 #include "lldb/Core/FileLineResolver.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Core/ModuleSpec.h"
15 #include "lldb/Core/SourceManager.h"
16 #include "lldb/Host/OptionParser.h"
17 #include "lldb/Interpreter/CommandReturnObject.h"
18 #include "lldb/Interpreter/OptionArgParser.h"
19 #include "lldb/Interpreter/Options.h"
20 #include "lldb/Symbol/CompileUnit.h"
21 #include "lldb/Symbol/Function.h"
22 #include "lldb/Symbol/Symbol.h"
23 #include "lldb/Target/SectionLoadList.h"
24 #include "lldb/Target/StackFrame.h"
25 #include "lldb/Utility/FileSpec.h"
28 using namespace lldb_private
;
30 #pragma mark CommandObjectSourceInfo
31 // CommandObjectSourceInfo - debug line entries dumping command
32 #define LLDB_OPTIONS_source_info
33 #include "CommandOptions.inc"
35 class CommandObjectSourceInfo
: public CommandObjectParsed
{
36 class CommandOptions
: public Options
{
38 CommandOptions() : Options() {}
40 ~CommandOptions() override
= default;
42 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
43 ExecutionContext
*execution_context
) override
{
45 const int short_option
= GetDefinitions()[option_idx
].short_option
;
46 switch (short_option
) {
48 if (option_arg
.getAsInteger(0, start_line
))
49 error
.SetErrorStringWithFormat("invalid line number: '%s'",
50 option_arg
.str().c_str());
54 if (option_arg
.getAsInteger(0, end_line
))
55 error
.SetErrorStringWithFormat("invalid line number: '%s'",
56 option_arg
.str().c_str());
60 if (option_arg
.getAsInteger(0, num_lines
))
61 error
.SetErrorStringWithFormat("invalid line count: '%s'",
62 option_arg
.str().c_str());
66 file_name
= option_arg
;
70 symbol_name
= option_arg
;
74 address
= OptionArgParser::ToAddress(execution_context
, option_arg
,
75 LLDB_INVALID_ADDRESS
, &error
);
78 modules
.push_back(std::string(option_arg
));
81 llvm_unreachable("Unimplemented option");
87 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
91 address
= LLDB_INVALID_ADDRESS
;
98 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
99 return llvm::makeArrayRef(g_source_info_options
);
102 // Instance variables to hold the values for command options.
104 std::string file_name
;
105 std::string symbol_name
;
106 lldb::addr_t address
;
110 std::vector
<std::string
> modules
;
114 CommandObjectSourceInfo(CommandInterpreter
&interpreter
)
115 : CommandObjectParsed(
116 interpreter
, "source info",
117 "Display source line information for the current target "
118 "process. Defaults to instruction pointer in current stack "
120 nullptr, eCommandRequiresTarget
),
123 ~CommandObjectSourceInfo() override
= default;
125 Options
*GetOptions() override
{ return &m_options
; }
128 // Dump the line entries in each symbol context. Return the number of entries
129 // found. If module_list is set, only dump lines contained in one of the
130 // modules. If file_spec is set, only dump lines in the file. If the
131 // start_line option was specified, don't print lines less than start_line.
132 // If the end_line option was specified, don't print lines greater than
133 // end_line. If the num_lines option was specified, dont print more than
134 // num_lines entries.
135 uint32_t DumpLinesInSymbolContexts(Stream
&strm
,
136 const SymbolContextList
&sc_list
,
137 const ModuleList
&module_list
,
138 const FileSpec
&file_spec
) {
139 uint32_t start_line
= m_options
.start_line
;
140 uint32_t end_line
= m_options
.end_line
;
141 uint32_t num_lines
= m_options
.num_lines
;
142 Target
*target
= m_exe_ctx
.GetTargetPtr();
144 uint32_t num_matches
= 0;
145 // Dump all the line entries for the file in the list.
146 ConstString last_module_file_name
;
147 uint32_t num_scs
= sc_list
.GetSize();
148 for (uint32_t i
= 0; i
< num_scs
; ++i
) {
150 sc_list
.GetContextAtIndex(i
, sc
);
152 Module
*module
= sc
.module_sp
.get();
153 CompileUnit
*cu
= sc
.comp_unit
;
154 const LineEntry
&line_entry
= sc
.line_entry
;
155 assert(module
&& cu
);
157 // Are we looking for specific modules, files or lines?
158 if (module_list
.GetSize() &&
159 module_list
.GetIndexForModule(module
) == LLDB_INVALID_INDEX32
)
161 if (!FileSpec::Match(file_spec
, line_entry
.file
))
163 if (start_line
> 0 && line_entry
.line
< start_line
)
165 if (end_line
> 0 && line_entry
.line
> end_line
)
167 if (num_lines
> 0 && num_matches
> num_lines
)
170 // Print a new header if the module changed.
171 ConstString module_file_name
= module
->GetFileSpec().GetFilename();
172 assert(module_file_name
);
173 if (module_file_name
!= last_module_file_name
) {
176 strm
<< "Lines found in module `" << module_file_name
<< "\n";
178 // Dump the line entry.
179 line_entry
.GetDescription(&strm
, lldb::eDescriptionLevelBrief
, cu
,
180 target
, /*show_address_only=*/false);
182 last_module_file_name
= module_file_name
;
189 // Dump the requested line entries for the file in the compilation unit.
190 // Return the number of entries found. If module_list is set, only dump lines
191 // contained in one of the modules. If the start_line option was specified,
192 // don't print lines less than start_line. If the end_line option was
193 // specified, don't print lines greater than end_line. If the num_lines
194 // option was specified, dont print more than num_lines entries.
195 uint32_t DumpFileLinesInCompUnit(Stream
&strm
, Module
*module
,
196 CompileUnit
*cu
, const FileSpec
&file_spec
) {
197 uint32_t start_line
= m_options
.start_line
;
198 uint32_t end_line
= m_options
.end_line
;
199 uint32_t num_lines
= m_options
.num_lines
;
200 Target
*target
= m_exe_ctx
.GetTargetPtr();
202 uint32_t num_matches
= 0;
205 assert(file_spec
.GetFilename().AsCString());
206 bool has_path
= (file_spec
.GetDirectory().AsCString() != nullptr);
207 const FileSpecList
&cu_file_list
= cu
->GetSupportFiles();
208 size_t file_idx
= cu_file_list
.FindFileIndex(0, file_spec
, has_path
);
209 if (file_idx
!= UINT32_MAX
) {
210 // Update the file to how it appears in the CU.
211 const FileSpec
&cu_file_spec
=
212 cu_file_list
.GetFileSpecAtIndex(file_idx
);
214 // Dump all matching lines at or above start_line for the file in the
216 ConstString file_spec_name
= file_spec
.GetFilename();
217 ConstString module_file_name
= module
->GetFileSpec().GetFilename();
218 bool cu_header_printed
= false;
219 uint32_t line
= start_line
;
221 LineEntry line_entry
;
223 // Find the lowest index of a line entry with a line equal to or
224 // higher than 'line'.
225 uint32_t start_idx
= 0;
226 start_idx
= cu
->FindLineEntry(start_idx
, line
, &cu_file_spec
,
227 /*exact=*/false, &line_entry
);
228 if (start_idx
== UINT32_MAX
)
229 // No more line entries for our file in this CU.
232 if (end_line
> 0 && line_entry
.line
> end_line
)
235 // Loop through to find any other entries for this line, dumping
237 line
= line_entry
.line
;
240 if (num_lines
> 0 && num_matches
> num_lines
)
242 assert(cu_file_spec
== line_entry
.file
);
243 if (!cu_header_printed
) {
246 strm
<< "Lines found for file " << file_spec_name
247 << " in compilation unit "
248 << cu
->GetPrimaryFile().GetFilename() << " in `"
249 << module_file_name
<< "\n";
250 cu_header_printed
= true;
252 line_entry
.GetDescription(&strm
, lldb::eDescriptionLevelBrief
, cu
,
253 target
, /*show_address_only=*/false);
256 // Anymore after this one?
258 start_idx
= cu
->FindLineEntry(start_idx
, line
, &cu_file_spec
,
259 /*exact=*/true, &line_entry
);
260 } while (start_idx
!= UINT32_MAX
);
262 // Try the next higher line, starting over at start_idx 0.
270 // Dump the requested line entries for the file in the module. Return the
271 // number of entries found. If module_list is set, only dump lines contained
272 // in one of the modules. If the start_line option was specified, don't print
273 // lines less than start_line. If the end_line option was specified, don't
274 // print lines greater than end_line. If the num_lines option was specified,
275 // dont print more than num_lines entries.
276 uint32_t DumpFileLinesInModule(Stream
&strm
, Module
*module
,
277 const FileSpec
&file_spec
) {
278 uint32_t num_matches
= 0;
280 // Look through all the compilation units (CUs) in this module for ones
281 // that contain lines of code from this source file.
282 for (size_t i
= 0; i
< module
->GetNumCompileUnits(); i
++) {
283 // Look for a matching source file in this CU.
284 CompUnitSP
cu_sp(module
->GetCompileUnitAtIndex(i
));
287 DumpFileLinesInCompUnit(strm
, module
, cu_sp
.get(), file_spec
);
294 // Given an address and a list of modules, append the symbol contexts of all
295 // line entries containing the address found in the modules and return the
296 // count of matches. If none is found, return an error in 'error_strm'.
297 size_t GetSymbolContextsForAddress(const ModuleList
&module_list
,
299 SymbolContextList
&sc_list
,
300 StreamString
&error_strm
) {
302 size_t num_matches
= 0;
303 assert(module_list
.GetSize() > 0);
304 Target
*target
= m_exe_ctx
.GetTargetPtr();
305 if (target
->GetSectionLoadList().IsEmpty()) {
306 // The target isn't loaded yet, we need to lookup the file address in all
307 // modules. Note: the module list option does not apply to addresses.
308 const size_t num_modules
= module_list
.GetSize();
309 for (size_t i
= 0; i
< num_modules
; ++i
) {
310 ModuleSP
module_sp(module_list
.GetModuleAtIndex(i
));
313 if (module_sp
->ResolveFileAddress(addr
, so_addr
)) {
316 if (module_sp
->ResolveSymbolContextForAddress(
317 so_addr
, eSymbolContextEverything
, sc
) &
318 eSymbolContextLineEntry
) {
319 sc_list
.AppendIfUnique(sc
, /*merge_symbol_into_function=*/false);
324 if (num_matches
== 0)
325 error_strm
.Printf("Source information for file address 0x%" PRIx64
326 " not found in any modules.\n",
329 // The target has some things loaded, resolve this address to a compile
330 // unit + file + line and display
331 if (target
->GetSectionLoadList().ResolveLoadAddress(addr
, so_addr
)) {
332 ModuleSP
module_sp(so_addr
.GetModule());
333 // Check to make sure this module is in our list.
334 if (module_sp
&& module_list
.GetIndexForModule(module_sp
.get()) !=
335 LLDB_INVALID_INDEX32
) {
338 if (module_sp
->ResolveSymbolContextForAddress(
339 so_addr
, eSymbolContextEverything
, sc
) &
340 eSymbolContextLineEntry
) {
341 sc_list
.AppendIfUnique(sc
, /*merge_symbol_into_function=*/false);
344 StreamString addr_strm
;
345 so_addr
.Dump(&addr_strm
, nullptr,
346 Address::DumpStyleModuleWithFileAddress
);
348 "Address 0x%" PRIx64
" resolves to %s, but there is"
349 " no source information available for this address.\n",
350 addr
, addr_strm
.GetData());
353 StreamString addr_strm
;
354 so_addr
.Dump(&addr_strm
, nullptr,
355 Address::DumpStyleModuleWithFileAddress
);
356 error_strm
.Printf("Address 0x%" PRIx64
357 " resolves to %s, but it cannot"
358 " be found in any modules.\n",
359 addr
, addr_strm
.GetData());
362 error_strm
.Printf("Unable to resolve address 0x%" PRIx64
".\n", addr
);
367 // Dump the line entries found in functions matching the name specified in
369 bool DumpLinesInFunctions(CommandReturnObject
&result
) {
370 SymbolContextList sc_list_funcs
;
371 ConstString
name(m_options
.symbol_name
.c_str());
372 SymbolContextList sc_list_lines
;
373 Target
*target
= m_exe_ctx
.GetTargetPtr();
374 uint32_t addr_byte_size
= target
->GetArchitecture().GetAddressByteSize();
376 // Note: module_list can't be const& because FindFunctionSymbols isn't
378 ModuleList module_list
=
379 (m_module_list
.GetSize() > 0) ? m_module_list
: target
->GetImages();
380 module_list
.FindFunctions(name
, eFunctionNameTypeAuto
,
381 /*include_symbols=*/false,
382 /*include_inlines=*/true, sc_list_funcs
);
383 size_t num_matches
= sc_list_funcs
.GetSize();
386 // If we didn't find any functions with that name, try searching for
387 // symbols that line up exactly with function addresses.
388 SymbolContextList sc_list_symbols
;
389 module_list
.FindFunctionSymbols(name
, eFunctionNameTypeAuto
,
391 size_t num_symbol_matches
= sc_list_symbols
.GetSize();
392 for (size_t i
= 0; i
< num_symbol_matches
; i
++) {
394 sc_list_symbols
.GetContextAtIndex(i
, sc
);
395 if (sc
.symbol
&& sc
.symbol
->ValueIsAddress()) {
396 const Address
&base_address
= sc
.symbol
->GetAddressRef();
397 Function
*function
= base_address
.CalculateSymbolContextFunction();
399 sc_list_funcs
.Append(SymbolContext(function
));
405 if (num_matches
== 0) {
406 result
.AppendErrorWithFormat("Could not find function named \'%s\'.\n",
407 m_options
.symbol_name
.c_str());
410 for (size_t i
= 0; i
< num_matches
; i
++) {
412 sc_list_funcs
.GetContextAtIndex(i
, sc
);
413 bool context_found_for_symbol
= false;
414 // Loop through all the ranges in the function.
417 sc
.GetAddressRange(eSymbolContextEverything
, r
,
418 /*use_inline_block_range=*/true, range
);
420 // Append the symbol contexts for each address in the range to
422 const Address
&base_address
= range
.GetBaseAddress();
423 const addr_t size
= range
.GetByteSize();
424 lldb::addr_t start_addr
= base_address
.GetLoadAddress(target
);
425 if (start_addr
== LLDB_INVALID_ADDRESS
)
426 start_addr
= base_address
.GetFileAddress();
427 lldb::addr_t end_addr
= start_addr
+ size
;
428 for (lldb::addr_t addr
= start_addr
; addr
< end_addr
;
429 addr
+= addr_byte_size
) {
430 StreamString error_strm
;
431 if (!GetSymbolContextsForAddress(module_list
, addr
, sc_list_lines
,
433 result
.AppendWarningWithFormat("in symbol '%s': %s",
434 sc
.GetFunctionName().AsCString(),
435 error_strm
.GetData());
437 context_found_for_symbol
= true;
440 if (!context_found_for_symbol
)
441 result
.AppendWarningWithFormat("Unable to find line information"
442 " for matching symbol '%s'.\n",
443 sc
.GetFunctionName().AsCString());
445 if (sc_list_lines
.GetSize() == 0) {
446 result
.AppendErrorWithFormat("No line information could be found"
447 " for any symbols matching '%s'.\n",
452 if (!DumpLinesInSymbolContexts(result
.GetOutputStream(), sc_list_lines
,
453 module_list
, file_spec
)) {
454 result
.AppendErrorWithFormat(
455 "Unable to dump line information for symbol '%s'.\n",
462 // Dump the line entries found for the address specified in the option.
463 bool DumpLinesForAddress(CommandReturnObject
&result
) {
464 Target
*target
= m_exe_ctx
.GetTargetPtr();
465 SymbolContextList sc_list
;
467 StreamString error_strm
;
468 if (!GetSymbolContextsForAddress(target
->GetImages(), m_options
.address
,
469 sc_list
, error_strm
)) {
470 result
.AppendErrorWithFormat("%s.\n", error_strm
.GetData());
473 ModuleList module_list
;
475 if (!DumpLinesInSymbolContexts(result
.GetOutputStream(), sc_list
,
476 module_list
, file_spec
)) {
477 result
.AppendErrorWithFormat("No modules contain load address 0x%" PRIx64
485 // Dump the line entries found in the file specified in the option.
486 bool DumpLinesForFile(CommandReturnObject
&result
) {
487 FileSpec
file_spec(m_options
.file_name
);
488 const char *filename
= m_options
.file_name
.c_str();
489 Target
*target
= m_exe_ctx
.GetTargetPtr();
490 const ModuleList
&module_list
=
491 (m_module_list
.GetSize() > 0) ? m_module_list
: target
->GetImages();
493 bool displayed_something
= false;
494 const size_t num_modules
= module_list
.GetSize();
495 for (uint32_t i
= 0; i
< num_modules
; ++i
) {
496 // Dump lines for this module.
497 Module
*module
= module_list
.GetModulePointerAtIndex(i
);
499 if (DumpFileLinesInModule(result
.GetOutputStream(), module
, file_spec
))
500 displayed_something
= true;
502 if (!displayed_something
) {
503 result
.AppendErrorWithFormat("No source filenames matched '%s'.\n",
510 // Dump the line entries for the current frame.
511 bool DumpLinesForFrame(CommandReturnObject
&result
) {
512 StackFrame
*cur_frame
= m_exe_ctx
.GetFramePtr();
513 if (cur_frame
== nullptr) {
515 "No selected frame to use to find the default source.");
517 } else if (!cur_frame
->HasDebugInformation()) {
518 result
.AppendError("No debug info for the selected frame.");
521 const SymbolContext
&sc
=
522 cur_frame
->GetSymbolContext(eSymbolContextLineEntry
);
523 SymbolContextList sc_list
;
525 ModuleList module_list
;
527 if (!DumpLinesInSymbolContexts(result
.GetOutputStream(), sc_list
,
528 module_list
, file_spec
)) {
530 "No source line info available for the selected frame.");
537 bool DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
538 const size_t argc
= command
.GetArgumentCount();
541 result
.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n",
542 GetCommandName().str().c_str());
543 result
.SetStatus(eReturnStatusFailed
);
547 Target
*target
= m_exe_ctx
.GetTargetPtr();
548 if (target
== nullptr) {
549 target
= GetDebugger().GetSelectedTarget().get();
550 if (target
== nullptr) {
551 result
.AppendError("invalid target, create a debug target using the "
552 "'target create' command.");
553 result
.SetStatus(eReturnStatusFailed
);
558 uint32_t addr_byte_size
= target
->GetArchitecture().GetAddressByteSize();
559 result
.GetOutputStream().SetAddressByteSize(addr_byte_size
);
560 result
.GetErrorStream().SetAddressByteSize(addr_byte_size
);
562 // Collect the list of modules to search.
563 m_module_list
.Clear();
564 if (!m_options
.modules
.empty()) {
565 for (size_t i
= 0, e
= m_options
.modules
.size(); i
< e
; ++i
) {
566 FileSpec
module_file_spec(m_options
.modules
[i
]);
567 if (module_file_spec
) {
568 ModuleSpec
module_spec(module_file_spec
);
569 target
->GetImages().FindModules(module_spec
, m_module_list
);
570 if (m_module_list
.IsEmpty())
571 result
.AppendWarningWithFormat("No module found for '%s'.\n",
572 m_options
.modules
[i
].c_str());
575 if (!m_module_list
.GetSize()) {
576 result
.AppendError("No modules match the input.");
577 result
.SetStatus(eReturnStatusFailed
);
580 } else if (target
->GetImages().GetSize() == 0) {
581 result
.AppendError("The target has no associated executable images.");
582 result
.SetStatus(eReturnStatusFailed
);
586 // Check the arguments to see what lines we should dump.
587 if (!m_options
.symbol_name
.empty()) {
588 // Print lines for symbol.
589 if (DumpLinesInFunctions(result
))
590 result
.SetStatus(eReturnStatusSuccessFinishResult
);
592 result
.SetStatus(eReturnStatusFailed
);
593 } else if (m_options
.address
!= LLDB_INVALID_ADDRESS
) {
594 // Print lines for an address.
595 if (DumpLinesForAddress(result
))
596 result
.SetStatus(eReturnStatusSuccessFinishResult
);
598 result
.SetStatus(eReturnStatusFailed
);
599 } else if (!m_options
.file_name
.empty()) {
600 // Dump lines for a file.
601 if (DumpLinesForFile(result
))
602 result
.SetStatus(eReturnStatusSuccessFinishResult
);
604 result
.SetStatus(eReturnStatusFailed
);
606 // Dump the line for the current frame.
607 if (DumpLinesForFrame(result
))
608 result
.SetStatus(eReturnStatusSuccessFinishResult
);
610 result
.SetStatus(eReturnStatusFailed
);
612 return result
.Succeeded();
615 CommandOptions m_options
;
616 ModuleList m_module_list
;
619 #pragma mark CommandObjectSourceList
620 // CommandObjectSourceList
621 #define LLDB_OPTIONS_source_list
622 #include "CommandOptions.inc"
624 class CommandObjectSourceList
: public CommandObjectParsed
{
625 class CommandOptions
: public Options
{
627 CommandOptions() : Options() {}
629 ~CommandOptions() override
= default;
631 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
632 ExecutionContext
*execution_context
) override
{
634 const int short_option
= GetDefinitions()[option_idx
].short_option
;
635 switch (short_option
) {
637 if (option_arg
.getAsInteger(0, start_line
))
638 error
.SetErrorStringWithFormat("invalid line number: '%s'",
639 option_arg
.str().c_str());
643 if (option_arg
.getAsInteger(0, num_lines
))
644 error
.SetErrorStringWithFormat("invalid line count: '%s'",
645 option_arg
.str().c_str());
649 file_name
= option_arg
;
653 symbol_name
= option_arg
;
657 address
= OptionArgParser::ToAddress(execution_context
, option_arg
,
658 LLDB_INVALID_ADDRESS
, &error
);
661 modules
.push_back(std::string(option_arg
));
671 llvm_unreachable("Unimplemented option");
677 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
681 address
= LLDB_INVALID_ADDRESS
;
684 show_bp_locs
= false;
689 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
690 return llvm::makeArrayRef(g_source_list_options
);
693 // Instance variables to hold the values for command options.
695 std::string file_name
;
696 std::string symbol_name
;
697 lldb::addr_t address
;
700 std::vector
<std::string
> modules
;
706 CommandObjectSourceList(CommandInterpreter
&interpreter
)
707 : CommandObjectParsed(interpreter
, "source list",
708 "Display source code for the current target "
709 "process as specified by options.",
710 nullptr, eCommandRequiresTarget
),
713 ~CommandObjectSourceList() override
= default;
715 Options
*GetOptions() override
{ return &m_options
; }
717 const char *GetRepeatCommand(Args
¤t_command_args
,
718 uint32_t index
) override
{
719 // This is kind of gross, but the command hasn't been parsed yet so we
720 // can't look at the option values for this invocation... I have to scan
721 // the arguments directly.
723 llvm::find_if(current_command_args
, [](const Args::ArgEntry
&e
) {
724 return e
.ref() == "-r" || e
.ref() == "--reverse";
726 if (iter
== current_command_args
.end())
727 return m_cmd_name
.c_str();
729 if (m_reverse_name
.empty()) {
730 m_reverse_name
= m_cmd_name
;
731 m_reverse_name
.append(" -r");
733 return m_reverse_name
.c_str();
738 ConstString function
;
739 LineEntry line_entry
;
741 SourceInfo(ConstString name
, const LineEntry
&line_entry
)
742 : function(name
), line_entry(line_entry
) {}
744 SourceInfo() : function(), line_entry() {}
746 bool IsValid() const { return (bool)function
&& line_entry
.IsValid(); }
748 bool operator==(const SourceInfo
&rhs
) const {
749 return function
== rhs
.function
&&
750 line_entry
.original_file
== rhs
.line_entry
.original_file
&&
751 line_entry
.line
== rhs
.line_entry
.line
;
754 bool operator!=(const SourceInfo
&rhs
) const {
755 return function
!= rhs
.function
||
756 line_entry
.original_file
!= rhs
.line_entry
.original_file
||
757 line_entry
.line
!= rhs
.line_entry
.line
;
760 bool operator<(const SourceInfo
&rhs
) const {
761 if (function
.GetCString() < rhs
.function
.GetCString())
763 if (line_entry
.file
.GetDirectory().GetCString() <
764 rhs
.line_entry
.file
.GetDirectory().GetCString())
766 if (line_entry
.file
.GetFilename().GetCString() <
767 rhs
.line_entry
.file
.GetFilename().GetCString())
769 if (line_entry
.line
< rhs
.line_entry
.line
)
775 size_t DisplayFunctionSource(const SymbolContext
&sc
, SourceInfo
&source_info
,
776 CommandReturnObject
&result
) {
777 if (!source_info
.IsValid()) {
778 source_info
.function
= sc
.GetFunctionName();
779 source_info
.line_entry
= sc
.GetFunctionStartLineEntry();
783 Target
*target
= m_exe_ctx
.GetTargetPtr();
790 if (sc
.block
== nullptr) {
791 // Not an inlined function
792 sc
.function
->GetStartLineSourceInfo(start_file
, start_line
);
793 if (start_line
== 0) {
794 result
.AppendErrorWithFormat("Could not find line information for "
795 "start of function: \"%s\".\n",
796 source_info
.function
.GetCString());
797 result
.SetStatus(eReturnStatusFailed
);
800 sc
.function
->GetEndLineSourceInfo(end_file
, end_line
);
802 // We have an inlined function
803 start_file
= source_info
.line_entry
.file
;
804 start_line
= source_info
.line_entry
.line
;
805 end_line
= start_line
+ m_options
.num_lines
;
808 // This is a little hacky, but the first line table entry for a function
809 // points to the "{" that starts the function block. It would be nice to
810 // actually get the function declaration in there too. So back up a bit,
811 // but not further than what you're going to display.
812 uint32_t extra_lines
;
813 if (m_options
.num_lines
>= 10)
816 extra_lines
= m_options
.num_lines
/ 2;
818 if (start_line
<= extra_lines
)
821 line_no
= start_line
- extra_lines
;
823 // For fun, if the function is shorter than the number of lines we're
824 // supposed to display, only display the function...
826 if (m_options
.num_lines
> end_line
- line_no
)
827 m_options
.num_lines
= end_line
- line_no
+ extra_lines
;
830 m_breakpoint_locations
.Clear();
832 if (m_options
.show_bp_locs
) {
833 const bool show_inlines
= true;
834 m_breakpoint_locations
.Reset(start_file
, 0, show_inlines
);
835 SearchFilterForUnconstrainedSearches
target_search_filter(
836 m_exe_ctx
.GetTargetSP());
837 target_search_filter
.Search(m_breakpoint_locations
);
840 result
.AppendMessageWithFormat("File: %s\n",
841 start_file
.GetPath().c_str());
842 // We don't care about the column here.
843 const uint32_t column
= 0;
844 return target
->GetSourceManager().DisplaySourceLinesWithLineNumbers(
845 start_file
, line_no
, column
, 0, m_options
.num_lines
, "",
846 &result
.GetOutputStream(), GetBreakpointLocations());
848 result
.AppendErrorWithFormat(
849 "Could not find function info for: \"%s\".\n",
850 m_options
.symbol_name
.c_str());
855 // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols
856 // functions "take a possibly empty vector of strings which are names of
857 // modules, and run the two search functions on the subset of the full module
858 // list that matches the strings in the input vector". If we wanted to put
859 // these somewhere, there should probably be a module-filter-list that can be
860 // passed to the various ModuleList::Find* calls, which would either be a
861 // vector of string names or a ModuleSpecList.
862 void FindMatchingFunctions(Target
*target
, ConstString name
,
863 SymbolContextList
&sc_list
) {
864 // Displaying the source for a symbol:
865 bool include_inlines
= true;
866 bool include_symbols
= false;
868 if (m_options
.num_lines
== 0)
869 m_options
.num_lines
= 10;
871 const size_t num_modules
= m_options
.modules
.size();
872 if (num_modules
> 0) {
873 ModuleList matching_modules
;
874 for (size_t i
= 0; i
< num_modules
; ++i
) {
875 FileSpec
module_file_spec(m_options
.modules
[i
]);
876 if (module_file_spec
) {
877 ModuleSpec
module_spec(module_file_spec
);
878 matching_modules
.Clear();
879 target
->GetImages().FindModules(module_spec
, matching_modules
);
880 matching_modules
.FindFunctions(name
, eFunctionNameTypeAuto
,
881 include_symbols
, include_inlines
,
886 target
->GetImages().FindFunctions(name
, eFunctionNameTypeAuto
,
887 include_symbols
, include_inlines
,
892 void FindMatchingFunctionSymbols(Target
*target
, ConstString name
,
893 SymbolContextList
&sc_list
) {
894 const size_t num_modules
= m_options
.modules
.size();
895 if (num_modules
> 0) {
896 ModuleList matching_modules
;
897 for (size_t i
= 0; i
< num_modules
; ++i
) {
898 FileSpec
module_file_spec(m_options
.modules
[i
]);
899 if (module_file_spec
) {
900 ModuleSpec
module_spec(module_file_spec
);
901 matching_modules
.Clear();
902 target
->GetImages().FindModules(module_spec
, matching_modules
);
903 matching_modules
.FindFunctionSymbols(name
, eFunctionNameTypeAuto
,
908 target
->GetImages().FindFunctionSymbols(name
, eFunctionNameTypeAuto
,
913 bool DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
914 const size_t argc
= command
.GetArgumentCount();
917 result
.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n",
918 GetCommandName().str().c_str());
919 result
.SetStatus(eReturnStatusFailed
);
923 Target
*target
= m_exe_ctx
.GetTargetPtr();
925 if (!m_options
.symbol_name
.empty()) {
926 SymbolContextList sc_list
;
927 ConstString
name(m_options
.symbol_name
.c_str());
929 // Displaying the source for a symbol. Search for function named name.
930 FindMatchingFunctions(target
, name
, sc_list
);
931 size_t num_matches
= sc_list
.GetSize();
933 // If we didn't find any functions with that name, try searching for
934 // symbols that line up exactly with function addresses.
935 SymbolContextList sc_list_symbols
;
936 FindMatchingFunctionSymbols(target
, name
, sc_list_symbols
);
937 size_t num_symbol_matches
= sc_list_symbols
.GetSize();
939 for (size_t i
= 0; i
< num_symbol_matches
; i
++) {
941 sc_list_symbols
.GetContextAtIndex(i
, sc
);
942 if (sc
.symbol
&& sc
.symbol
->ValueIsAddress()) {
943 const Address
&base_address
= sc
.symbol
->GetAddressRef();
944 Function
*function
= base_address
.CalculateSymbolContextFunction();
946 sc_list
.Append(SymbolContext(function
));
954 if (num_matches
== 0) {
955 result
.AppendErrorWithFormat("Could not find function named: \"%s\".\n",
956 m_options
.symbol_name
.c_str());
957 result
.SetStatus(eReturnStatusFailed
);
961 if (num_matches
> 1) {
962 std::set
<SourceInfo
> source_match_set
;
964 bool displayed_something
= false;
965 for (size_t i
= 0; i
< num_matches
; i
++) {
967 sc_list
.GetContextAtIndex(i
, sc
);
968 SourceInfo
source_info(sc
.GetFunctionName(),
969 sc
.GetFunctionStartLineEntry());
971 if (source_info
.IsValid()) {
972 if (source_match_set
.find(source_info
) == source_match_set
.end()) {
973 source_match_set
.insert(source_info
);
974 if (DisplayFunctionSource(sc
, source_info
, result
))
975 displayed_something
= true;
980 if (displayed_something
)
981 result
.SetStatus(eReturnStatusSuccessFinishResult
);
983 result
.SetStatus(eReturnStatusFailed
);
986 sc_list
.GetContextAtIndex(0, sc
);
987 SourceInfo source_info
;
989 if (DisplayFunctionSource(sc
, source_info
, result
)) {
990 result
.SetStatus(eReturnStatusSuccessFinishResult
);
992 result
.SetStatus(eReturnStatusFailed
);
995 return result
.Succeeded();
996 } else if (m_options
.address
!= LLDB_INVALID_ADDRESS
) {
998 StreamString error_strm
;
999 SymbolContextList sc_list
;
1001 if (target
->GetSectionLoadList().IsEmpty()) {
1002 // The target isn't loaded yet, we need to lookup the file address in
1004 const ModuleList
&module_list
= target
->GetImages();
1005 const size_t num_modules
= module_list
.GetSize();
1006 for (size_t i
= 0; i
< num_modules
; ++i
) {
1007 ModuleSP
module_sp(module_list
.GetModuleAtIndex(i
));
1009 module_sp
->ResolveFileAddress(m_options
.address
, so_addr
)) {
1012 if (module_sp
->ResolveSymbolContextForAddress(
1013 so_addr
, eSymbolContextEverything
, sc
) &
1014 eSymbolContextLineEntry
)
1019 if (sc_list
.GetSize() == 0) {
1020 result
.AppendErrorWithFormat(
1021 "no modules have source information for file address 0x%" PRIx64
1024 result
.SetStatus(eReturnStatusFailed
);
1028 // The target has some things loaded, resolve this address to a compile
1029 // unit + file + line and display
1030 if (target
->GetSectionLoadList().ResolveLoadAddress(m_options
.address
,
1032 ModuleSP
module_sp(so_addr
.GetModule());
1036 if (module_sp
->ResolveSymbolContextForAddress(
1037 so_addr
, eSymbolContextEverything
, sc
) &
1038 eSymbolContextLineEntry
) {
1041 so_addr
.Dump(&error_strm
, nullptr,
1042 Address::DumpStyleModuleWithFileAddress
);
1043 result
.AppendErrorWithFormat("address resolves to %s, but there "
1044 "is no line table information "
1045 "available for this address.\n",
1046 error_strm
.GetData());
1047 result
.SetStatus(eReturnStatusFailed
);
1053 if (sc_list
.GetSize() == 0) {
1054 result
.AppendErrorWithFormat(
1055 "no modules contain load address 0x%" PRIx64
".\n",
1057 result
.SetStatus(eReturnStatusFailed
);
1061 uint32_t num_matches
= sc_list
.GetSize();
1062 for (uint32_t i
= 0; i
< num_matches
; ++i
) {
1064 sc_list
.GetContextAtIndex(i
, sc
);
1066 if (m_options
.show_bp_locs
) {
1067 m_breakpoint_locations
.Clear();
1068 const bool show_inlines
= true;
1069 m_breakpoint_locations
.Reset(sc
.comp_unit
->GetPrimaryFile(), 0,
1071 SearchFilterForUnconstrainedSearches
target_search_filter(
1072 target
->shared_from_this());
1073 target_search_filter
.Search(m_breakpoint_locations
);
1076 bool show_fullpaths
= true;
1077 bool show_module
= true;
1078 bool show_inlined_frames
= true;
1079 const bool show_function_arguments
= true;
1080 const bool show_function_name
= true;
1081 sc
.DumpStopContext(&result
.GetOutputStream(),
1082 m_exe_ctx
.GetBestExecutionContextScope(),
1083 sc
.line_entry
.range
.GetBaseAddress(),
1084 show_fullpaths
, show_module
, show_inlined_frames
,
1085 show_function_arguments
, show_function_name
);
1086 result
.GetOutputStream().EOL();
1088 if (m_options
.num_lines
== 0)
1089 m_options
.num_lines
= 10;
1091 size_t lines_to_back_up
=
1092 m_options
.num_lines
>= 10 ? 5 : m_options
.num_lines
/ 2;
1094 const uint32_t column
=
1095 (GetDebugger().GetStopShowColumn() != eStopShowColumnNone
)
1096 ? sc
.line_entry
.column
1098 target
->GetSourceManager().DisplaySourceLinesWithLineNumbers(
1099 sc
.comp_unit
->GetPrimaryFile(), sc
.line_entry
.line
, column
,
1100 lines_to_back_up
, m_options
.num_lines
- lines_to_back_up
, "->",
1101 &result
.GetOutputStream(), GetBreakpointLocations());
1102 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1105 } else if (m_options
.file_name
.empty()) {
1106 // Last valid source manager context, or the current frame if no valid
1107 // last context in source manager. One little trick here, if you type the
1108 // exact same list command twice in a row, it is more likely because you
1109 // typed it once, then typed it again
1110 if (m_options
.start_line
== 0) {
1111 if (target
->GetSourceManager().DisplayMoreWithLineNumbers(
1112 &result
.GetOutputStream(), m_options
.num_lines
,
1113 m_options
.reverse
, GetBreakpointLocations())) {
1114 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1117 if (m_options
.num_lines
== 0)
1118 m_options
.num_lines
= 10;
1120 if (m_options
.show_bp_locs
) {
1121 SourceManager::FileSP
last_file_sp(
1122 target
->GetSourceManager().GetLastFile());
1124 const bool show_inlines
= true;
1125 m_breakpoint_locations
.Reset(last_file_sp
->GetFileSpec(), 0,
1127 SearchFilterForUnconstrainedSearches
target_search_filter(
1128 target
->shared_from_this());
1129 target_search_filter
.Search(m_breakpoint_locations
);
1132 m_breakpoint_locations
.Clear();
1134 const uint32_t column
= 0;
1135 if (target
->GetSourceManager()
1136 .DisplaySourceLinesWithLineNumbersUsingLastFile(
1137 m_options
.start_line
, // Line to display
1138 m_options
.num_lines
, // Lines after line to
1139 UINT32_MAX
, // Don't mark "line"
1141 "", // Don't mark "line"
1142 &result
.GetOutputStream(), GetBreakpointLocations())) {
1143 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1147 const char *filename
= m_options
.file_name
.c_str();
1149 bool check_inlines
= false;
1150 SymbolContextList sc_list
;
1151 size_t num_matches
= 0;
1153 if (!m_options
.modules
.empty()) {
1154 ModuleList matching_modules
;
1155 for (size_t i
= 0, e
= m_options
.modules
.size(); i
< e
; ++i
) {
1156 FileSpec
module_file_spec(m_options
.modules
[i
]);
1157 if (module_file_spec
) {
1158 ModuleSpec
module_spec(module_file_spec
);
1159 matching_modules
.Clear();
1160 target
->GetImages().FindModules(module_spec
, matching_modules
);
1161 num_matches
+= matching_modules
.ResolveSymbolContextForFilePath(
1162 filename
, 0, check_inlines
,
1163 SymbolContextItem(eSymbolContextModule
|
1164 eSymbolContextCompUnit
),
1169 num_matches
= target
->GetImages().ResolveSymbolContextForFilePath(
1170 filename
, 0, check_inlines
,
1171 eSymbolContextModule
| eSymbolContextCompUnit
, sc_list
);
1174 if (num_matches
== 0) {
1175 result
.AppendErrorWithFormat("Could not find source file \"%s\".\n",
1176 m_options
.file_name
.c_str());
1177 result
.SetStatus(eReturnStatusFailed
);
1181 if (num_matches
> 1) {
1182 bool got_multiple
= false;
1183 CompileUnit
*test_cu
= nullptr;
1185 for (unsigned i
= 0; i
< num_matches
; i
++) {
1187 sc_list
.GetContextAtIndex(i
, sc
);
1190 if (test_cu
!= sc
.comp_unit
)
1191 got_multiple
= true;
1194 test_cu
= sc
.comp_unit
;
1198 result
.AppendErrorWithFormat(
1199 "Multiple source files found matching: \"%s.\"\n",
1200 m_options
.file_name
.c_str());
1201 result
.SetStatus(eReturnStatusFailed
);
1207 if (sc_list
.GetContextAtIndex(0, sc
)) {
1209 if (m_options
.show_bp_locs
) {
1210 const bool show_inlines
= true;
1211 m_breakpoint_locations
.Reset(sc
.comp_unit
->GetPrimaryFile(), 0,
1213 SearchFilterForUnconstrainedSearches
target_search_filter(
1214 target
->shared_from_this());
1215 target_search_filter
.Search(m_breakpoint_locations
);
1217 m_breakpoint_locations
.Clear();
1219 if (m_options
.num_lines
== 0)
1220 m_options
.num_lines
= 10;
1221 const uint32_t column
= 0;
1222 target
->GetSourceManager().DisplaySourceLinesWithLineNumbers(
1223 sc
.comp_unit
->GetPrimaryFile(), m_options
.start_line
, column
, 0,
1224 m_options
.num_lines
, "", &result
.GetOutputStream(),
1225 GetBreakpointLocations());
1227 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1229 result
.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n",
1230 m_options
.file_name
.c_str());
1231 result
.SetStatus(eReturnStatusFailed
);
1236 return result
.Succeeded();
1239 const SymbolContextList
*GetBreakpointLocations() {
1240 if (m_breakpoint_locations
.GetFileLineMatches().GetSize() > 0)
1241 return &m_breakpoint_locations
.GetFileLineMatches();
1245 CommandOptions m_options
;
1246 FileLineResolver m_breakpoint_locations
;
1247 std::string m_reverse_name
;
1250 #pragma mark CommandObjectMultiwordSource
1251 // CommandObjectMultiwordSource
1253 CommandObjectMultiwordSource::CommandObjectMultiwordSource(
1254 CommandInterpreter
&interpreter
)
1255 : CommandObjectMultiword(interpreter
, "source",
1256 "Commands for examining "
1257 "source code described by "
1258 "debug information for the "
1259 "current target process.",
1260 "source <subcommand> [<subcommand-options>]") {
1261 LoadSubCommand("info",
1262 CommandObjectSP(new CommandObjectSourceInfo(interpreter
)));
1263 LoadSubCommand("list",
1264 CommandObjectSP(new CommandObjectSourceList(interpreter
)));
1267 CommandObjectMultiwordSource::~CommandObjectMultiwordSource() = default;