1 //===-- CommandObjectSource.cpp -------------------------------------------===//
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/CommandOptionArgumentTable.h"
18 #include "lldb/Interpreter/CommandReturnObject.h"
19 #include "lldb/Interpreter/OptionArgParser.h"
20 #include "lldb/Interpreter/OptionValueFileColonLine.h"
21 #include "lldb/Interpreter/Options.h"
22 #include "lldb/Symbol/CompileUnit.h"
23 #include "lldb/Symbol/Function.h"
24 #include "lldb/Symbol/Symbol.h"
25 #include "lldb/Target/Process.h"
26 #include "lldb/Target/SectionLoadList.h"
27 #include "lldb/Target/StackFrame.h"
28 #include "lldb/Utility/FileSpec.h"
32 using namespace lldb_private
;
34 #pragma mark CommandObjectSourceInfo
35 // CommandObjectSourceInfo - debug line entries dumping command
36 #define LLDB_OPTIONS_source_info
37 #include "CommandOptions.inc"
39 class CommandObjectSourceInfo
: public CommandObjectParsed
{
40 class CommandOptions
: public Options
{
42 CommandOptions() = default;
44 ~CommandOptions() override
= default;
46 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
47 ExecutionContext
*execution_context
) override
{
49 const int short_option
= GetDefinitions()[option_idx
].short_option
;
50 switch (short_option
) {
52 if (option_arg
.getAsInteger(0, start_line
))
53 error
= Status::FromErrorStringWithFormat("invalid line number: '%s'",
54 option_arg
.str().c_str());
58 if (option_arg
.getAsInteger(0, end_line
))
59 error
= Status::FromErrorStringWithFormat("invalid line number: '%s'",
60 option_arg
.str().c_str());
64 if (option_arg
.getAsInteger(0, num_lines
))
65 error
= Status::FromErrorStringWithFormat("invalid line count: '%s'",
66 option_arg
.str().c_str());
70 file_name
= std::string(option_arg
);
74 symbol_name
= std::string(option_arg
);
78 address
= OptionArgParser::ToAddress(execution_context
, option_arg
,
79 LLDB_INVALID_ADDRESS
, &error
);
82 modules
.push_back(std::string(option_arg
));
85 llvm_unreachable("Unimplemented option");
91 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
95 address
= LLDB_INVALID_ADDRESS
;
102 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
103 return llvm::ArrayRef(g_source_info_options
);
106 // Instance variables to hold the values for command options.
108 std::string file_name
;
109 std::string symbol_name
;
110 lldb::addr_t address
;
114 std::vector
<std::string
> modules
;
118 CommandObjectSourceInfo(CommandInterpreter
&interpreter
)
119 : CommandObjectParsed(
120 interpreter
, "source info",
121 "Display source line information for the current target "
122 "process. Defaults to instruction pointer in current stack "
124 nullptr, eCommandRequiresTarget
) {}
126 ~CommandObjectSourceInfo() override
= default;
128 Options
*GetOptions() override
{ return &m_options
; }
131 // Dump the line entries in each symbol context. Return the number of entries
132 // found. If module_list is set, only dump lines contained in one of the
133 // modules. If file_spec is set, only dump lines in the file. If the
134 // start_line option was specified, don't print lines less than start_line.
135 // If the end_line option was specified, don't print lines greater than
136 // end_line. If the num_lines option was specified, dont print more than
137 // num_lines entries.
138 uint32_t DumpLinesInSymbolContexts(Stream
&strm
,
139 const SymbolContextList
&sc_list
,
140 const ModuleList
&module_list
,
141 const FileSpec
&file_spec
) {
142 uint32_t start_line
= m_options
.start_line
;
143 uint32_t end_line
= m_options
.end_line
;
144 uint32_t num_lines
= m_options
.num_lines
;
145 Target
&target
= GetTarget();
147 uint32_t num_matches
= 0;
148 // Dump all the line entries for the file in the list.
149 ConstString last_module_file_name
;
150 for (const SymbolContext
&sc
: sc_list
) {
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
.GetFile()))
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
= GetTarget();
202 uint32_t num_matches
= 0;
205 assert(file_spec
.GetFilename().AsCString());
206 bool has_path
= (file_spec
.GetDirectory().AsCString() != nullptr);
207 const SupportFileList
&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
.GetFile());
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
= GetTarget();
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
= GetTarget();
374 uint32_t addr_byte_size
= target
.GetArchitecture().GetAddressByteSize();
376 ModuleFunctionSearchOptions function_options
;
377 function_options
.include_symbols
= false;
378 function_options
.include_inlines
= true;
380 // Note: module_list can't be const& because FindFunctionSymbols isn't
382 ModuleList module_list
=
383 (m_module_list
.GetSize() > 0) ? m_module_list
: target
.GetImages();
384 module_list
.FindFunctions(name
, eFunctionNameTypeAuto
, function_options
,
386 size_t num_matches
= sc_list_funcs
.GetSize();
389 // If we didn't find any functions with that name, try searching for
390 // symbols that line up exactly with function addresses.
391 SymbolContextList sc_list_symbols
;
392 module_list
.FindFunctionSymbols(name
, eFunctionNameTypeAuto
,
394 for (const SymbolContext
&sc
: sc_list_symbols
) {
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 (const SymbolContext
&sc
: sc_list_funcs
) {
411 bool context_found_for_symbol
= false;
412 // Loop through all the ranges in the function.
415 sc
.GetAddressRange(eSymbolContextEverything
, r
,
416 /*use_inline_block_range=*/true, range
);
418 // Append the symbol contexts for each address in the range to
420 const Address
&base_address
= range
.GetBaseAddress();
421 const addr_t size
= range
.GetByteSize();
422 lldb::addr_t start_addr
= base_address
.GetLoadAddress(&target
);
423 if (start_addr
== LLDB_INVALID_ADDRESS
)
424 start_addr
= base_address
.GetFileAddress();
425 lldb::addr_t end_addr
= start_addr
+ size
;
426 for (lldb::addr_t addr
= start_addr
; addr
< end_addr
;
427 addr
+= addr_byte_size
) {
428 StreamString error_strm
;
429 if (!GetSymbolContextsForAddress(module_list
, addr
, sc_list_lines
,
431 result
.AppendWarningWithFormat("in symbol '%s': %s",
432 sc
.GetFunctionName().AsCString(),
433 error_strm
.GetData());
435 context_found_for_symbol
= true;
438 if (!context_found_for_symbol
)
439 result
.AppendWarningWithFormat("Unable to find line information"
440 " for matching symbol '%s'.\n",
441 sc
.GetFunctionName().AsCString());
443 if (sc_list_lines
.GetSize() == 0) {
444 result
.AppendErrorWithFormat("No line information could be found"
445 " for any symbols matching '%s'.\n",
450 if (!DumpLinesInSymbolContexts(result
.GetOutputStream(), sc_list_lines
,
451 module_list
, file_spec
)) {
452 result
.AppendErrorWithFormat(
453 "Unable to dump line information for symbol '%s'.\n",
460 // Dump the line entries found for the address specified in the option.
461 bool DumpLinesForAddress(CommandReturnObject
&result
) {
462 Target
&target
= GetTarget();
463 SymbolContextList sc_list
;
465 StreamString error_strm
;
466 if (!GetSymbolContextsForAddress(target
.GetImages(), m_options
.address
,
467 sc_list
, error_strm
)) {
468 result
.AppendErrorWithFormat("%s.\n", error_strm
.GetData());
471 ModuleList module_list
;
473 if (!DumpLinesInSymbolContexts(result
.GetOutputStream(), sc_list
,
474 module_list
, file_spec
)) {
475 result
.AppendErrorWithFormat("No modules contain load address 0x%" PRIx64
483 // Dump the line entries found in the file specified in the option.
484 bool DumpLinesForFile(CommandReturnObject
&result
) {
485 FileSpec
file_spec(m_options
.file_name
);
486 const char *filename
= m_options
.file_name
.c_str();
487 Target
&target
= GetTarget();
488 const ModuleList
&module_list
=
489 (m_module_list
.GetSize() > 0) ? m_module_list
: target
.GetImages();
491 bool displayed_something
= false;
492 const size_t num_modules
= module_list
.GetSize();
493 for (uint32_t i
= 0; i
< num_modules
; ++i
) {
494 // Dump lines for this module.
495 Module
*module
= module_list
.GetModulePointerAtIndex(i
);
497 if (DumpFileLinesInModule(result
.GetOutputStream(), module
, file_spec
))
498 displayed_something
= true;
500 if (!displayed_something
) {
501 result
.AppendErrorWithFormat("No source filenames matched '%s'.\n",
508 // Dump the line entries for the current frame.
509 bool DumpLinesForFrame(CommandReturnObject
&result
) {
510 StackFrame
*cur_frame
= m_exe_ctx
.GetFramePtr();
511 if (cur_frame
== nullptr) {
513 "No selected frame to use to find the default source.");
515 } else if (!cur_frame
->HasDebugInformation()) {
516 result
.AppendError("No debug info for the selected frame.");
519 const SymbolContext
&sc
=
520 cur_frame
->GetSymbolContext(eSymbolContextLineEntry
);
521 SymbolContextList sc_list
;
523 ModuleList module_list
;
525 if (!DumpLinesInSymbolContexts(result
.GetOutputStream(), sc_list
,
526 module_list
, file_spec
)) {
528 "No source line info available for the selected frame.");
535 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
536 Target
&target
= GetTarget();
538 uint32_t addr_byte_size
= target
.GetArchitecture().GetAddressByteSize();
539 result
.GetOutputStream().SetAddressByteSize(addr_byte_size
);
540 result
.GetErrorStream().SetAddressByteSize(addr_byte_size
);
542 // Collect the list of modules to search.
543 m_module_list
.Clear();
544 if (!m_options
.modules
.empty()) {
545 for (size_t i
= 0, e
= m_options
.modules
.size(); i
< e
; ++i
) {
546 FileSpec
module_file_spec(m_options
.modules
[i
]);
547 if (module_file_spec
) {
548 ModuleSpec
module_spec(module_file_spec
);
549 target
.GetImages().FindModules(module_spec
, m_module_list
);
550 if (m_module_list
.IsEmpty())
551 result
.AppendWarningWithFormat("No module found for '%s'.\n",
552 m_options
.modules
[i
].c_str());
555 if (!m_module_list
.GetSize()) {
556 result
.AppendError("No modules match the input.");
559 } else if (target
.GetImages().GetSize() == 0) {
560 result
.AppendError("The target has no associated executable images.");
564 // Check the arguments to see what lines we should dump.
565 if (!m_options
.symbol_name
.empty()) {
566 // Print lines for symbol.
567 if (DumpLinesInFunctions(result
))
568 result
.SetStatus(eReturnStatusSuccessFinishResult
);
570 result
.SetStatus(eReturnStatusFailed
);
571 } else if (m_options
.address
!= LLDB_INVALID_ADDRESS
) {
572 // Print lines for an address.
573 if (DumpLinesForAddress(result
))
574 result
.SetStatus(eReturnStatusSuccessFinishResult
);
576 result
.SetStatus(eReturnStatusFailed
);
577 } else if (!m_options
.file_name
.empty()) {
578 // Dump lines for a file.
579 if (DumpLinesForFile(result
))
580 result
.SetStatus(eReturnStatusSuccessFinishResult
);
582 result
.SetStatus(eReturnStatusFailed
);
584 // Dump the line for the current frame.
585 if (DumpLinesForFrame(result
))
586 result
.SetStatus(eReturnStatusSuccessFinishResult
);
588 result
.SetStatus(eReturnStatusFailed
);
592 CommandOptions m_options
;
593 ModuleList m_module_list
;
596 #pragma mark CommandObjectSourceList
597 // CommandObjectSourceList
598 #define LLDB_OPTIONS_source_list
599 #include "CommandOptions.inc"
601 class CommandObjectSourceList
: public CommandObjectParsed
{
602 class CommandOptions
: public Options
{
604 CommandOptions() = default;
606 ~CommandOptions() override
= default;
608 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
609 ExecutionContext
*execution_context
) override
{
611 const int short_option
= GetDefinitions()[option_idx
].short_option
;
612 switch (short_option
) {
614 if (option_arg
.getAsInteger(0, start_line
))
615 error
= Status::FromErrorStringWithFormat("invalid line number: '%s'",
616 option_arg
.str().c_str());
620 if (option_arg
.getAsInteger(0, num_lines
))
621 error
= Status::FromErrorStringWithFormat("invalid line count: '%s'",
622 option_arg
.str().c_str());
626 file_name
= std::string(option_arg
);
630 symbol_name
= std::string(option_arg
);
634 address
= OptionArgParser::ToAddress(execution_context
, option_arg
,
635 LLDB_INVALID_ADDRESS
, &error
);
638 modules
.push_back(std::string(option_arg
));
649 OptionValueFileColonLine value
;
650 Status fcl_err
= value
.SetValueFromString(option_arg
);
651 if (!fcl_err
.Success()) {
652 error
= Status::FromErrorStringWithFormat(
653 "Invalid value for file:line specifier: %s", fcl_err
.AsCString());
655 file_name
= value
.GetFileSpec().GetPath();
656 start_line
= value
.GetLineNumber();
657 // I don't see anything useful to do with a column number, but I don't
658 // want to complain since someone may well have cut and pasted a
659 // listing from somewhere that included a column.
663 llvm_unreachable("Unimplemented option");
669 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
673 address
= LLDB_INVALID_ADDRESS
;
676 show_bp_locs
= false;
681 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
682 return llvm::ArrayRef(g_source_list_options
);
685 // Instance variables to hold the values for command options.
687 std::string file_name
;
688 std::string symbol_name
;
689 lldb::addr_t address
;
692 std::vector
<std::string
> modules
;
698 CommandObjectSourceList(CommandInterpreter
&interpreter
)
699 : CommandObjectParsed(interpreter
, "source list",
700 "Display source code for the current target "
701 "process as specified by options.",
702 nullptr, eCommandRequiresTarget
) {}
704 ~CommandObjectSourceList() override
= default;
706 Options
*GetOptions() override
{ return &m_options
; }
708 std::optional
<std::string
> GetRepeatCommand(Args
¤t_command_args
,
709 uint32_t index
) override
{
710 // This is kind of gross, but the command hasn't been parsed yet so we
711 // can't look at the option values for this invocation... I have to scan
712 // the arguments directly.
714 llvm::find_if(current_command_args
, [](const Args::ArgEntry
&e
) {
715 return e
.ref() == "-r" || e
.ref() == "--reverse";
717 if (iter
== current_command_args
.end())
720 if (m_reverse_name
.empty()) {
721 m_reverse_name
= m_cmd_name
;
722 m_reverse_name
.append(" -r");
724 return m_reverse_name
;
729 ConstString function
;
730 LineEntry line_entry
;
732 SourceInfo(ConstString name
, const LineEntry
&line_entry
)
733 : function(name
), line_entry(line_entry
) {}
735 SourceInfo() = default;
737 bool IsValid() const { return (bool)function
&& line_entry
.IsValid(); }
739 bool operator==(const SourceInfo
&rhs
) const {
740 return function
== rhs
.function
&&
741 line_entry
.original_file_sp
->Equal(
742 *rhs
.line_entry
.original_file_sp
,
743 SupportFile::eEqualFileSpecAndChecksumIfSet
) &&
744 line_entry
.line
== rhs
.line_entry
.line
;
747 bool operator!=(const SourceInfo
&rhs
) const {
748 return function
!= rhs
.function
||
749 !line_entry
.original_file_sp
->Equal(
750 *rhs
.line_entry
.original_file_sp
,
751 SupportFile::eEqualFileSpecAndChecksumIfSet
) ||
752 line_entry
.line
!= rhs
.line_entry
.line
;
755 bool operator<(const SourceInfo
&rhs
) const {
756 if (function
.GetCString() < rhs
.function
.GetCString())
758 if (line_entry
.GetFile().GetDirectory().GetCString() <
759 rhs
.line_entry
.GetFile().GetDirectory().GetCString())
761 if (line_entry
.GetFile().GetFilename().GetCString() <
762 rhs
.line_entry
.GetFile().GetFilename().GetCString())
764 if (line_entry
.line
< rhs
.line_entry
.line
)
770 size_t DisplayFunctionSource(const SymbolContext
&sc
, SourceInfo
&source_info
,
771 CommandReturnObject
&result
) {
772 if (!source_info
.IsValid()) {
773 source_info
.function
= sc
.GetFunctionName();
774 source_info
.line_entry
= sc
.GetFunctionStartLineEntry();
778 Target
&target
= GetTarget();
780 SupportFileSP start_file
= std::make_shared
<SupportFile
>();
785 if (sc
.block
== nullptr) {
786 // Not an inlined function
787 sc
.function
->GetStartLineSourceInfo(start_file
, start_line
);
788 if (start_line
== 0) {
789 result
.AppendErrorWithFormat("Could not find line information for "
790 "start of function: \"%s\".\n",
791 source_info
.function
.GetCString());
794 sc
.function
->GetEndLineSourceInfo(end_file
, end_line
);
796 // We have an inlined function
797 start_file
= source_info
.line_entry
.file_sp
;
798 start_line
= source_info
.line_entry
.line
;
799 end_line
= start_line
+ m_options
.num_lines
;
802 // This is a little hacky, but the first line table entry for a function
803 // points to the "{" that starts the function block. It would be nice to
804 // actually get the function declaration in there too. So back up a bit,
805 // but not further than what you're going to display.
806 uint32_t extra_lines
;
807 if (m_options
.num_lines
>= 10)
810 extra_lines
= m_options
.num_lines
/ 2;
812 if (start_line
<= extra_lines
)
815 line_no
= start_line
- extra_lines
;
817 // For fun, if the function is shorter than the number of lines we're
818 // supposed to display, only display the function...
820 if (m_options
.num_lines
> end_line
- line_no
)
821 m_options
.num_lines
= end_line
- line_no
+ extra_lines
;
824 m_breakpoint_locations
.Clear();
826 if (m_options
.show_bp_locs
) {
827 const bool show_inlines
= true;
828 m_breakpoint_locations
.Reset(start_file
->GetSpecOnly(), 0,
830 SearchFilterForUnconstrainedSearches
target_search_filter(
831 m_exe_ctx
.GetTargetSP());
832 target_search_filter
.Search(m_breakpoint_locations
);
835 result
.AppendMessageWithFormat(
836 "File: %s\n", start_file
->GetSpecOnly().GetPath().c_str());
837 // We don't care about the column here.
838 const uint32_t column
= 0;
839 return target
.GetSourceManager().DisplaySourceLinesWithLineNumbers(
840 start_file
, line_no
, column
, 0, m_options
.num_lines
, "",
841 &result
.GetOutputStream(), GetBreakpointLocations());
843 result
.AppendErrorWithFormat(
844 "Could not find function info for: \"%s\".\n",
845 m_options
.symbol_name
.c_str());
850 // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols
851 // functions "take a possibly empty vector of strings which are names of
852 // modules, and run the two search functions on the subset of the full module
853 // list that matches the strings in the input vector". If we wanted to put
854 // these somewhere, there should probably be a module-filter-list that can be
855 // passed to the various ModuleList::Find* calls, which would either be a
856 // vector of string names or a ModuleSpecList.
857 void FindMatchingFunctions(Target
&target
, ConstString name
,
858 SymbolContextList
&sc_list
) {
859 // Displaying the source for a symbol:
860 if (m_options
.num_lines
== 0)
861 m_options
.num_lines
= 10;
863 ModuleFunctionSearchOptions function_options
;
864 function_options
.include_symbols
= true;
865 function_options
.include_inlines
= false;
867 const size_t num_modules
= m_options
.modules
.size();
868 if (num_modules
> 0) {
869 ModuleList matching_modules
;
870 for (size_t i
= 0; i
< num_modules
; ++i
) {
871 FileSpec
module_file_spec(m_options
.modules
[i
]);
872 if (module_file_spec
) {
873 ModuleSpec
module_spec(module_file_spec
);
874 matching_modules
.Clear();
875 target
.GetImages().FindModules(module_spec
, matching_modules
);
877 matching_modules
.FindFunctions(name
, eFunctionNameTypeAuto
,
878 function_options
, sc_list
);
882 target
.GetImages().FindFunctions(name
, eFunctionNameTypeAuto
,
883 function_options
, sc_list
);
887 void FindMatchingFunctionSymbols(Target
&target
, ConstString name
,
888 SymbolContextList
&sc_list
) {
889 const size_t num_modules
= m_options
.modules
.size();
890 if (num_modules
> 0) {
891 ModuleList matching_modules
;
892 for (size_t i
= 0; i
< num_modules
; ++i
) {
893 FileSpec
module_file_spec(m_options
.modules
[i
]);
894 if (module_file_spec
) {
895 ModuleSpec
module_spec(module_file_spec
);
896 matching_modules
.Clear();
897 target
.GetImages().FindModules(module_spec
, matching_modules
);
898 matching_modules
.FindFunctionSymbols(name
, eFunctionNameTypeAuto
,
903 target
.GetImages().FindFunctionSymbols(name
, eFunctionNameTypeAuto
,
908 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
909 Target
&target
= GetTarget();
911 if (!m_options
.symbol_name
.empty()) {
912 SymbolContextList sc_list
;
913 ConstString
name(m_options
.symbol_name
.c_str());
915 // Displaying the source for a symbol. Search for function named name.
916 FindMatchingFunctions(target
, name
, sc_list
);
917 if (sc_list
.GetSize() == 0) {
918 // If we didn't find any functions with that name, try searching for
919 // symbols that line up exactly with function addresses.
920 SymbolContextList sc_list_symbols
;
921 FindMatchingFunctionSymbols(target
, name
, sc_list_symbols
);
922 for (const SymbolContext
&sc
: sc_list_symbols
) {
923 if (sc
.symbol
&& sc
.symbol
->ValueIsAddress()) {
924 const Address
&base_address
= sc
.symbol
->GetAddressRef();
925 Function
*function
= base_address
.CalculateSymbolContextFunction();
927 sc_list
.Append(SymbolContext(function
));
934 if (sc_list
.GetSize() == 0) {
935 result
.AppendErrorWithFormat("Could not find function named: \"%s\".\n",
936 m_options
.symbol_name
.c_str());
940 std::set
<SourceInfo
> source_match_set
;
941 bool displayed_something
= false;
942 for (const SymbolContext
&sc
: sc_list
) {
943 SourceInfo
source_info(sc
.GetFunctionName(),
944 sc
.GetFunctionStartLineEntry());
945 if (source_info
.IsValid() &&
946 source_match_set
.find(source_info
) == source_match_set
.end()) {
947 source_match_set
.insert(source_info
);
948 if (DisplayFunctionSource(sc
, source_info
, result
))
949 displayed_something
= true;
952 if (displayed_something
)
953 result
.SetStatus(eReturnStatusSuccessFinishResult
);
955 result
.SetStatus(eReturnStatusFailed
);
957 } else if (m_options
.address
!= LLDB_INVALID_ADDRESS
) {
959 StreamString error_strm
;
960 SymbolContextList sc_list
;
962 if (target
.GetSectionLoadList().IsEmpty()) {
963 // The target isn't loaded yet, we need to lookup the file address in
965 const ModuleList
&module_list
= target
.GetImages();
966 const size_t num_modules
= module_list
.GetSize();
967 for (size_t i
= 0; i
< num_modules
; ++i
) {
968 ModuleSP
module_sp(module_list
.GetModuleAtIndex(i
));
970 module_sp
->ResolveFileAddress(m_options
.address
, so_addr
)) {
973 if (module_sp
->ResolveSymbolContextForAddress(
974 so_addr
, eSymbolContextEverything
, sc
) &
975 eSymbolContextLineEntry
)
980 if (sc_list
.GetSize() == 0) {
981 result
.AppendErrorWithFormat(
982 "no modules have source information for file address 0x%" PRIx64
988 // The target has some things loaded, resolve this address to a compile
989 // unit + file + line and display
990 if (target
.GetSectionLoadList().ResolveLoadAddress(m_options
.address
,
992 ModuleSP
module_sp(so_addr
.GetModule());
996 if (module_sp
->ResolveSymbolContextForAddress(
997 so_addr
, eSymbolContextEverything
, sc
) &
998 eSymbolContextLineEntry
) {
1001 so_addr
.Dump(&error_strm
, nullptr,
1002 Address::DumpStyleModuleWithFileAddress
);
1003 result
.AppendErrorWithFormat("address resolves to %s, but there "
1004 "is no line table information "
1005 "available for this address.\n",
1006 error_strm
.GetData());
1012 if (sc_list
.GetSize() == 0) {
1013 result
.AppendErrorWithFormat(
1014 "no modules contain load address 0x%" PRIx64
".\n",
1019 for (const SymbolContext
&sc
: sc_list
) {
1021 if (m_options
.show_bp_locs
) {
1022 m_breakpoint_locations
.Clear();
1023 const bool show_inlines
= true;
1024 m_breakpoint_locations
.Reset(sc
.comp_unit
->GetPrimaryFile(), 0,
1026 SearchFilterForUnconstrainedSearches
target_search_filter(
1027 target
.shared_from_this());
1028 target_search_filter
.Search(m_breakpoint_locations
);
1031 bool show_fullpaths
= true;
1032 bool show_module
= true;
1033 bool show_inlined_frames
= true;
1034 const bool show_function_arguments
= true;
1035 const bool show_function_name
= true;
1036 sc
.DumpStopContext(&result
.GetOutputStream(),
1037 m_exe_ctx
.GetBestExecutionContextScope(),
1038 sc
.line_entry
.range
.GetBaseAddress(),
1039 show_fullpaths
, show_module
, show_inlined_frames
,
1040 show_function_arguments
, show_function_name
);
1041 result
.GetOutputStream().EOL();
1043 if (m_options
.num_lines
== 0)
1044 m_options
.num_lines
= 10;
1046 size_t lines_to_back_up
=
1047 m_options
.num_lines
>= 10 ? 5 : m_options
.num_lines
/ 2;
1049 const uint32_t column
=
1050 (GetDebugger().GetStopShowColumn() != eStopShowColumnNone
)
1051 ? sc
.line_entry
.column
1053 target
.GetSourceManager().DisplaySourceLinesWithLineNumbers(
1054 sc
.comp_unit
->GetPrimarySupportFile(),
1055 sc
.line_entry
.line
, column
, lines_to_back_up
,
1056 m_options
.num_lines
- lines_to_back_up
, "->",
1057 &result
.GetOutputStream(), GetBreakpointLocations());
1058 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1061 } else if (m_options
.file_name
.empty()) {
1062 // Last valid source manager context, or the current frame if no valid
1063 // last context in source manager. One little trick here, if you type the
1064 // exact same list command twice in a row, it is more likely because you
1065 // typed it once, then typed it again
1066 if (m_options
.start_line
== 0) {
1067 if (target
.GetSourceManager().DisplayMoreWithLineNumbers(
1068 &result
.GetOutputStream(), m_options
.num_lines
,
1069 m_options
.reverse
, GetBreakpointLocations())) {
1070 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1073 if (m_options
.num_lines
== 0)
1074 m_options
.num_lines
= 10;
1076 if (m_options
.show_bp_locs
) {
1077 SourceManager::FileSP
last_file_sp(
1078 target
.GetSourceManager().GetLastFile());
1080 const bool show_inlines
= true;
1081 m_breakpoint_locations
.Reset(
1082 last_file_sp
->GetSupportFile()->GetSpecOnly(), 0, show_inlines
);
1083 SearchFilterForUnconstrainedSearches
target_search_filter(
1084 target
.shared_from_this());
1085 target_search_filter
.Search(m_breakpoint_locations
);
1088 m_breakpoint_locations
.Clear();
1090 const uint32_t column
= 0;
1091 if (target
.GetSourceManager()
1092 .DisplaySourceLinesWithLineNumbersUsingLastFile(
1093 m_options
.start_line
, // Line to display
1094 m_options
.num_lines
, // Lines after line to
1095 UINT32_MAX
, // Don't mark "line"
1097 "", // Don't mark "line"
1098 &result
.GetOutputStream(), GetBreakpointLocations())) {
1099 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1103 const char *filename
= m_options
.file_name
.c_str();
1105 bool check_inlines
= false;
1106 SymbolContextList sc_list
;
1107 size_t num_matches
= 0;
1109 if (!m_options
.modules
.empty()) {
1110 ModuleList matching_modules
;
1111 for (size_t i
= 0, e
= m_options
.modules
.size(); i
< e
; ++i
) {
1112 FileSpec
module_file_spec(m_options
.modules
[i
]);
1113 if (module_file_spec
) {
1114 ModuleSpec
module_spec(module_file_spec
);
1115 matching_modules
.Clear();
1116 target
.GetImages().FindModules(module_spec
, matching_modules
);
1117 num_matches
+= matching_modules
.ResolveSymbolContextForFilePath(
1118 filename
, 0, check_inlines
,
1119 SymbolContextItem(eSymbolContextModule
|
1120 eSymbolContextCompUnit
),
1125 num_matches
= target
.GetImages().ResolveSymbolContextForFilePath(
1126 filename
, 0, check_inlines
,
1127 eSymbolContextModule
| eSymbolContextCompUnit
, sc_list
);
1130 if (num_matches
== 0) {
1131 result
.AppendErrorWithFormat("Could not find source file \"%s\".\n",
1132 m_options
.file_name
.c_str());
1136 if (num_matches
> 1) {
1137 bool got_multiple
= false;
1138 CompileUnit
*test_cu
= nullptr;
1140 for (const SymbolContext
&sc
: sc_list
) {
1143 if (test_cu
!= sc
.comp_unit
)
1144 got_multiple
= true;
1147 test_cu
= sc
.comp_unit
;
1151 result
.AppendErrorWithFormat(
1152 "Multiple source files found matching: \"%s.\"\n",
1153 m_options
.file_name
.c_str());
1159 if (sc_list
.GetContextAtIndex(0, sc
)) {
1161 if (m_options
.show_bp_locs
) {
1162 const bool show_inlines
= true;
1163 m_breakpoint_locations
.Reset(sc
.comp_unit
->GetPrimaryFile(), 0,
1165 SearchFilterForUnconstrainedSearches
target_search_filter(
1166 target
.shared_from_this());
1167 target_search_filter
.Search(m_breakpoint_locations
);
1169 m_breakpoint_locations
.Clear();
1171 if (m_options
.num_lines
== 0)
1172 m_options
.num_lines
= 10;
1173 const uint32_t column
= 0;
1174 target
.GetSourceManager().DisplaySourceLinesWithLineNumbers(
1175 sc
.comp_unit
->GetPrimarySupportFile(),
1176 m_options
.start_line
, column
, 0, m_options
.num_lines
, "",
1177 &result
.GetOutputStream(), GetBreakpointLocations());
1179 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1181 result
.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n",
1182 m_options
.file_name
.c_str());
1188 const SymbolContextList
*GetBreakpointLocations() {
1189 if (m_breakpoint_locations
.GetFileLineMatches().GetSize() > 0)
1190 return &m_breakpoint_locations
.GetFileLineMatches();
1194 CommandOptions m_options
;
1195 FileLineResolver m_breakpoint_locations
;
1196 std::string m_reverse_name
;
1199 class CommandObjectSourceCacheDump
: public CommandObjectParsed
{
1201 CommandObjectSourceCacheDump(CommandInterpreter
&interpreter
)
1202 : CommandObjectParsed(interpreter
, "source cache dump",
1203 "Dump the state of the source code cache. Intended "
1204 "to be used for debugging LLDB itself.",
1207 ~CommandObjectSourceCacheDump() override
= default;
1210 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
1211 // Dump the debugger source cache.
1212 result
.GetOutputStream() << "Debugger Source File Cache\n";
1213 SourceManager::SourceFileCache
&cache
= GetDebugger().GetSourceFileCache();
1214 cache
.Dump(result
.GetOutputStream());
1216 // Dump the process source cache.
1217 if (ProcessSP process_sp
= m_exe_ctx
.GetProcessSP()) {
1218 result
.GetOutputStream() << "\nProcess Source File Cache\n";
1219 SourceManager::SourceFileCache
&cache
= process_sp
->GetSourceFileCache();
1220 cache
.Dump(result
.GetOutputStream());
1223 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1227 class CommandObjectSourceCacheClear
: public CommandObjectParsed
{
1229 CommandObjectSourceCacheClear(CommandInterpreter
&interpreter
)
1230 : CommandObjectParsed(interpreter
, "source cache clear",
1231 "Clear the source code cache.\n", nullptr) {}
1233 ~CommandObjectSourceCacheClear() override
= default;
1236 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
1237 // Clear the debugger cache.
1238 SourceManager::SourceFileCache
&cache
= GetDebugger().GetSourceFileCache();
1241 // Clear the process cache.
1242 if (ProcessSP process_sp
= m_exe_ctx
.GetProcessSP())
1243 process_sp
->GetSourceFileCache().Clear();
1245 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
1249 class CommandObjectSourceCache
: public CommandObjectMultiword
{
1251 CommandObjectSourceCache(CommandInterpreter
&interpreter
)
1252 : CommandObjectMultiword(interpreter
, "source cache",
1253 "Commands for managing the source code cache.",
1254 "source cache <sub-command>") {
1256 "dump", CommandObjectSP(new CommandObjectSourceCacheDump(interpreter
)));
1257 LoadSubCommand("clear", CommandObjectSP(new CommandObjectSourceCacheClear(
1261 ~CommandObjectSourceCache() override
= default;
1264 CommandObjectSourceCache(const CommandObjectSourceCache
&) = delete;
1265 const CommandObjectSourceCache
&
1266 operator=(const CommandObjectSourceCache
&) = delete;
1269 #pragma mark CommandObjectMultiwordSource
1270 // CommandObjectMultiwordSource
1272 CommandObjectMultiwordSource::CommandObjectMultiwordSource(
1273 CommandInterpreter
&interpreter
)
1274 : CommandObjectMultiword(interpreter
, "source",
1275 "Commands for examining "
1276 "source code described by "
1277 "debug information for the "
1278 "current target process.",
1279 "source <subcommand> [<subcommand-options>]") {
1280 LoadSubCommand("info",
1281 CommandObjectSP(new CommandObjectSourceInfo(interpreter
)));
1282 LoadSubCommand("list",
1283 CommandObjectSP(new CommandObjectSourceList(interpreter
)));
1284 LoadSubCommand("cache",
1285 CommandObjectSP(new CommandObjectSourceCache(interpreter
)));
1288 CommandObjectMultiwordSource::~CommandObjectMultiwordSource() = default;