15ffd83dbSDimitry Andric //===-- CommandObjectSource.cpp -------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "CommandObjectSource.h" 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #include "lldb/Core/Debugger.h" 120b57cec5SDimitry Andric #include "lldb/Core/FileLineResolver.h" 130b57cec5SDimitry Andric #include "lldb/Core/Module.h" 140b57cec5SDimitry Andric #include "lldb/Core/ModuleSpec.h" 150b57cec5SDimitry Andric #include "lldb/Core/SourceManager.h" 160b57cec5SDimitry Andric #include "lldb/Host/OptionParser.h" 17fcaf7f86SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h" 180b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 190b57cec5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h" 20e8d8bef9SDimitry Andric #include "lldb/Interpreter/OptionValueFileColonLine.h" 210b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h" 220b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h" 230b57cec5SDimitry Andric #include "lldb/Symbol/Function.h" 240b57cec5SDimitry Andric #include "lldb/Symbol/Symbol.h" 2506c3fb27SDimitry Andric #include "lldb/Target/Process.h" 260b57cec5SDimitry Andric #include "lldb/Target/SectionLoadList.h" 270b57cec5SDimitry Andric #include "lldb/Target/StackFrame.h" 280b57cec5SDimitry Andric #include "lldb/Utility/FileSpec.h" 29bdd1243dSDimitry Andric #include <optional> 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric using namespace lldb; 320b57cec5SDimitry Andric using namespace lldb_private; 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric #pragma mark CommandObjectSourceInfo 350b57cec5SDimitry Andric // CommandObjectSourceInfo - debug line entries dumping command 369dba64beSDimitry Andric #define LLDB_OPTIONS_source_info 379dba64beSDimitry Andric #include "CommandOptions.inc" 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric class CommandObjectSourceInfo : public CommandObjectParsed { 400b57cec5SDimitry Andric class CommandOptions : public Options { 410b57cec5SDimitry Andric public: 4281ad6265SDimitry Andric CommandOptions() = default; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric ~CommandOptions() override = default; 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 470b57cec5SDimitry Andric ExecutionContext *execution_context) override { 480b57cec5SDimitry Andric Status error; 490b57cec5SDimitry Andric const int short_option = GetDefinitions()[option_idx].short_option; 500b57cec5SDimitry Andric switch (short_option) { 510b57cec5SDimitry Andric case 'l': 520b57cec5SDimitry Andric if (option_arg.getAsInteger(0, start_line)) 530b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line number: '%s'", 540b57cec5SDimitry Andric option_arg.str().c_str()); 550b57cec5SDimitry Andric break; 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric case 'e': 580b57cec5SDimitry Andric if (option_arg.getAsInteger(0, end_line)) 590b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line number: '%s'", 600b57cec5SDimitry Andric option_arg.str().c_str()); 610b57cec5SDimitry Andric break; 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric case 'c': 640b57cec5SDimitry Andric if (option_arg.getAsInteger(0, num_lines)) 650b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line count: '%s'", 660b57cec5SDimitry Andric option_arg.str().c_str()); 670b57cec5SDimitry Andric break; 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric case 'f': 705ffd83dbSDimitry Andric file_name = std::string(option_arg); 710b57cec5SDimitry Andric break; 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric case 'n': 745ffd83dbSDimitry Andric symbol_name = std::string(option_arg); 750b57cec5SDimitry Andric break; 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric case 'a': { 780b57cec5SDimitry Andric address = OptionArgParser::ToAddress(execution_context, option_arg, 790b57cec5SDimitry Andric LLDB_INVALID_ADDRESS, &error); 800b57cec5SDimitry Andric } break; 810b57cec5SDimitry Andric case 's': 820b57cec5SDimitry Andric modules.push_back(std::string(option_arg)); 830b57cec5SDimitry Andric break; 840b57cec5SDimitry Andric default: 859dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric return error; 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 920b57cec5SDimitry Andric file_spec.Clear(); 930b57cec5SDimitry Andric file_name.clear(); 940b57cec5SDimitry Andric symbol_name.clear(); 950b57cec5SDimitry Andric address = LLDB_INVALID_ADDRESS; 960b57cec5SDimitry Andric start_line = 0; 970b57cec5SDimitry Andric end_line = 0; 980b57cec5SDimitry Andric num_lines = 0; 990b57cec5SDimitry Andric modules.clear(); 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 103bdd1243dSDimitry Andric return llvm::ArrayRef(g_source_info_options); 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric // Instance variables to hold the values for command options. 1070b57cec5SDimitry Andric FileSpec file_spec; 1080b57cec5SDimitry Andric std::string file_name; 1090b57cec5SDimitry Andric std::string symbol_name; 1100b57cec5SDimitry Andric lldb::addr_t address; 1110b57cec5SDimitry Andric uint32_t start_line; 1120b57cec5SDimitry Andric uint32_t end_line; 1130b57cec5SDimitry Andric uint32_t num_lines; 114480093f4SDimitry Andric std::vector<std::string> modules; 1150b57cec5SDimitry Andric }; 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric public: 1180b57cec5SDimitry Andric CommandObjectSourceInfo(CommandInterpreter &interpreter) 1190b57cec5SDimitry Andric : CommandObjectParsed( 1200b57cec5SDimitry Andric interpreter, "source info", 1210b57cec5SDimitry Andric "Display source line information for the current target " 1220b57cec5SDimitry Andric "process. Defaults to instruction pointer in current stack " 1230b57cec5SDimitry Andric "frame.", 12404eeddc0SDimitry Andric nullptr, eCommandRequiresTarget) {} 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric ~CommandObjectSourceInfo() override = default; 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric protected: 1310b57cec5SDimitry Andric // Dump the line entries in each symbol context. Return the number of entries 1320b57cec5SDimitry Andric // found. If module_list is set, only dump lines contained in one of the 1330b57cec5SDimitry Andric // modules. If file_spec is set, only dump lines in the file. If the 1340b57cec5SDimitry Andric // start_line option was specified, don't print lines less than start_line. 1350b57cec5SDimitry Andric // If the end_line option was specified, don't print lines greater than 1360b57cec5SDimitry Andric // end_line. If the num_lines option was specified, dont print more than 1370b57cec5SDimitry Andric // num_lines entries. 1380b57cec5SDimitry Andric uint32_t DumpLinesInSymbolContexts(Stream &strm, 1390b57cec5SDimitry Andric const SymbolContextList &sc_list, 1400b57cec5SDimitry Andric const ModuleList &module_list, 1410b57cec5SDimitry Andric const FileSpec &file_spec) { 1420b57cec5SDimitry Andric uint32_t start_line = m_options.start_line; 1430b57cec5SDimitry Andric uint32_t end_line = m_options.end_line; 1440b57cec5SDimitry Andric uint32_t num_lines = m_options.num_lines; 1450b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric uint32_t num_matches = 0; 1480b57cec5SDimitry Andric // Dump all the line entries for the file in the list. 1490b57cec5SDimitry Andric ConstString last_module_file_name; 15006c3fb27SDimitry Andric for (const SymbolContext &sc : sc_list) { 1510b57cec5SDimitry Andric if (sc.comp_unit) { 1520b57cec5SDimitry Andric Module *module = sc.module_sp.get(); 1530b57cec5SDimitry Andric CompileUnit *cu = sc.comp_unit; 1540b57cec5SDimitry Andric const LineEntry &line_entry = sc.line_entry; 1550b57cec5SDimitry Andric assert(module && cu); 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric // Are we looking for specific modules, files or lines? 1580b57cec5SDimitry Andric if (module_list.GetSize() && 1590b57cec5SDimitry Andric module_list.GetIndexForModule(module) == LLDB_INVALID_INDEX32) 1600b57cec5SDimitry Andric continue; 161*0fca6ea1SDimitry Andric if (!FileSpec::Match(file_spec, line_entry.GetFile())) 1620b57cec5SDimitry Andric continue; 1630b57cec5SDimitry Andric if (start_line > 0 && line_entry.line < start_line) 1640b57cec5SDimitry Andric continue; 1650b57cec5SDimitry Andric if (end_line > 0 && line_entry.line > end_line) 1660b57cec5SDimitry Andric continue; 1670b57cec5SDimitry Andric if (num_lines > 0 && num_matches > num_lines) 1680b57cec5SDimitry Andric continue; 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric // Print a new header if the module changed. 171480093f4SDimitry Andric ConstString module_file_name = module->GetFileSpec().GetFilename(); 1720b57cec5SDimitry Andric assert(module_file_name); 1730b57cec5SDimitry Andric if (module_file_name != last_module_file_name) { 1740b57cec5SDimitry Andric if (num_matches > 0) 1750b57cec5SDimitry Andric strm << "\n\n"; 1760b57cec5SDimitry Andric strm << "Lines found in module `" << module_file_name << "\n"; 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric // Dump the line entry. 1790b57cec5SDimitry Andric line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu, 1800b57cec5SDimitry Andric target, /*show_address_only=*/false); 1810b57cec5SDimitry Andric strm << "\n"; 1820b57cec5SDimitry Andric last_module_file_name = module_file_name; 1830b57cec5SDimitry Andric num_matches++; 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric return num_matches; 1870b57cec5SDimitry Andric } 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric // Dump the requested line entries for the file in the compilation unit. 1900b57cec5SDimitry Andric // Return the number of entries found. If module_list is set, only dump lines 1910b57cec5SDimitry Andric // contained in one of the modules. If the start_line option was specified, 1920b57cec5SDimitry Andric // don't print lines less than start_line. If the end_line option was 1930b57cec5SDimitry Andric // specified, don't print lines greater than end_line. If the num_lines 1940b57cec5SDimitry Andric // option was specified, dont print more than num_lines entries. 1950b57cec5SDimitry Andric uint32_t DumpFileLinesInCompUnit(Stream &strm, Module *module, 1960b57cec5SDimitry Andric CompileUnit *cu, const FileSpec &file_spec) { 1970b57cec5SDimitry Andric uint32_t start_line = m_options.start_line; 1980b57cec5SDimitry Andric uint32_t end_line = m_options.end_line; 1990b57cec5SDimitry Andric uint32_t num_lines = m_options.num_lines; 2000b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric uint32_t num_matches = 0; 2030b57cec5SDimitry Andric assert(module); 2040b57cec5SDimitry Andric if (cu) { 2050b57cec5SDimitry Andric assert(file_spec.GetFilename().AsCString()); 2060b57cec5SDimitry Andric bool has_path = (file_spec.GetDirectory().AsCString() != nullptr); 2071db9f3b2SDimitry Andric const SupportFileList &cu_file_list = cu->GetSupportFiles(); 2080b57cec5SDimitry Andric size_t file_idx = cu_file_list.FindFileIndex(0, file_spec, has_path); 2090b57cec5SDimitry Andric if (file_idx != UINT32_MAX) { 2100b57cec5SDimitry Andric // Update the file to how it appears in the CU. 2110b57cec5SDimitry Andric const FileSpec &cu_file_spec = 2120b57cec5SDimitry Andric cu_file_list.GetFileSpecAtIndex(file_idx); 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric // Dump all matching lines at or above start_line for the file in the 2150b57cec5SDimitry Andric // CU. 2160b57cec5SDimitry Andric ConstString file_spec_name = file_spec.GetFilename(); 217480093f4SDimitry Andric ConstString module_file_name = module->GetFileSpec().GetFilename(); 2180b57cec5SDimitry Andric bool cu_header_printed = false; 2190b57cec5SDimitry Andric uint32_t line = start_line; 2200b57cec5SDimitry Andric while (true) { 2210b57cec5SDimitry Andric LineEntry line_entry; 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric // Find the lowest index of a line entry with a line equal to or 2240b57cec5SDimitry Andric // higher than 'line'. 2250b57cec5SDimitry Andric uint32_t start_idx = 0; 2260b57cec5SDimitry Andric start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec, 2270b57cec5SDimitry Andric /*exact=*/false, &line_entry); 2280b57cec5SDimitry Andric if (start_idx == UINT32_MAX) 2290b57cec5SDimitry Andric // No more line entries for our file in this CU. 2300b57cec5SDimitry Andric break; 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric if (end_line > 0 && line_entry.line > end_line) 2330b57cec5SDimitry Andric break; 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric // Loop through to find any other entries for this line, dumping 2360b57cec5SDimitry Andric // each. 2370b57cec5SDimitry Andric line = line_entry.line; 2380b57cec5SDimitry Andric do { 2390b57cec5SDimitry Andric num_matches++; 2400b57cec5SDimitry Andric if (num_lines > 0 && num_matches > num_lines) 2410b57cec5SDimitry Andric break; 242*0fca6ea1SDimitry Andric assert(cu_file_spec == line_entry.GetFile()); 2430b57cec5SDimitry Andric if (!cu_header_printed) { 2440b57cec5SDimitry Andric if (num_matches > 0) 2450b57cec5SDimitry Andric strm << "\n\n"; 2460b57cec5SDimitry Andric strm << "Lines found for file " << file_spec_name 247480093f4SDimitry Andric << " in compilation unit " 248480093f4SDimitry Andric << cu->GetPrimaryFile().GetFilename() << " in `" 2490b57cec5SDimitry Andric << module_file_name << "\n"; 2500b57cec5SDimitry Andric cu_header_printed = true; 2510b57cec5SDimitry Andric } 2520b57cec5SDimitry Andric line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu, 2530b57cec5SDimitry Andric target, /*show_address_only=*/false); 2540b57cec5SDimitry Andric strm << "\n"; 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric // Anymore after this one? 2570b57cec5SDimitry Andric start_idx++; 2580b57cec5SDimitry Andric start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec, 2590b57cec5SDimitry Andric /*exact=*/true, &line_entry); 2600b57cec5SDimitry Andric } while (start_idx != UINT32_MAX); 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric // Try the next higher line, starting over at start_idx 0. 2630b57cec5SDimitry Andric line++; 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric } 2660b57cec5SDimitry Andric } 2670b57cec5SDimitry Andric return num_matches; 2680b57cec5SDimitry Andric } 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric // Dump the requested line entries for the file in the module. Return the 2710b57cec5SDimitry Andric // number of entries found. If module_list is set, only dump lines contained 2720b57cec5SDimitry Andric // in one of the modules. If the start_line option was specified, don't print 2730b57cec5SDimitry Andric // lines less than start_line. If the end_line option was specified, don't 2740b57cec5SDimitry Andric // print lines greater than end_line. If the num_lines option was specified, 2750b57cec5SDimitry Andric // dont print more than num_lines entries. 2760b57cec5SDimitry Andric uint32_t DumpFileLinesInModule(Stream &strm, Module *module, 2770b57cec5SDimitry Andric const FileSpec &file_spec) { 2780b57cec5SDimitry Andric uint32_t num_matches = 0; 2790b57cec5SDimitry Andric if (module) { 2800b57cec5SDimitry Andric // Look through all the compilation units (CUs) in this module for ones 2810b57cec5SDimitry Andric // that contain lines of code from this source file. 2820b57cec5SDimitry Andric for (size_t i = 0; i < module->GetNumCompileUnits(); i++) { 2830b57cec5SDimitry Andric // Look for a matching source file in this CU. 2840b57cec5SDimitry Andric CompUnitSP cu_sp(module->GetCompileUnitAtIndex(i)); 2850b57cec5SDimitry Andric if (cu_sp) { 2860b57cec5SDimitry Andric num_matches += 2870b57cec5SDimitry Andric DumpFileLinesInCompUnit(strm, module, cu_sp.get(), file_spec); 2880b57cec5SDimitry Andric } 2890b57cec5SDimitry Andric } 2900b57cec5SDimitry Andric } 2910b57cec5SDimitry Andric return num_matches; 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric // Given an address and a list of modules, append the symbol contexts of all 2950b57cec5SDimitry Andric // line entries containing the address found in the modules and return the 2960b57cec5SDimitry Andric // count of matches. If none is found, return an error in 'error_strm'. 2970b57cec5SDimitry Andric size_t GetSymbolContextsForAddress(const ModuleList &module_list, 2980b57cec5SDimitry Andric lldb::addr_t addr, 2990b57cec5SDimitry Andric SymbolContextList &sc_list, 3000b57cec5SDimitry Andric StreamString &error_strm) { 3010b57cec5SDimitry Andric Address so_addr; 3020b57cec5SDimitry Andric size_t num_matches = 0; 3030b57cec5SDimitry Andric assert(module_list.GetSize() > 0); 3040b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 3050b57cec5SDimitry Andric if (target->GetSectionLoadList().IsEmpty()) { 3060b57cec5SDimitry Andric // The target isn't loaded yet, we need to lookup the file address in all 3070b57cec5SDimitry Andric // modules. Note: the module list option does not apply to addresses. 3080b57cec5SDimitry Andric const size_t num_modules = module_list.GetSize(); 3090b57cec5SDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 3100b57cec5SDimitry Andric ModuleSP module_sp(module_list.GetModuleAtIndex(i)); 3110b57cec5SDimitry Andric if (!module_sp) 3120b57cec5SDimitry Andric continue; 3130b57cec5SDimitry Andric if (module_sp->ResolveFileAddress(addr, so_addr)) { 3140b57cec5SDimitry Andric SymbolContext sc; 3150b57cec5SDimitry Andric sc.Clear(true); 3160b57cec5SDimitry Andric if (module_sp->ResolveSymbolContextForAddress( 3170b57cec5SDimitry Andric so_addr, eSymbolContextEverything, sc) & 3180b57cec5SDimitry Andric eSymbolContextLineEntry) { 3190b57cec5SDimitry Andric sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false); 3200b57cec5SDimitry Andric ++num_matches; 3210b57cec5SDimitry Andric } 3220b57cec5SDimitry Andric } 3230b57cec5SDimitry Andric } 3240b57cec5SDimitry Andric if (num_matches == 0) 3250b57cec5SDimitry Andric error_strm.Printf("Source information for file address 0x%" PRIx64 3260b57cec5SDimitry Andric " not found in any modules.\n", 3270b57cec5SDimitry Andric addr); 3280b57cec5SDimitry Andric } else { 3290b57cec5SDimitry Andric // The target has some things loaded, resolve this address to a compile 3300b57cec5SDimitry Andric // unit + file + line and display 3310b57cec5SDimitry Andric if (target->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) { 3320b57cec5SDimitry Andric ModuleSP module_sp(so_addr.GetModule()); 3330b57cec5SDimitry Andric // Check to make sure this module is in our list. 334480093f4SDimitry Andric if (module_sp && module_list.GetIndexForModule(module_sp.get()) != 3350b57cec5SDimitry Andric LLDB_INVALID_INDEX32) { 3360b57cec5SDimitry Andric SymbolContext sc; 3370b57cec5SDimitry Andric sc.Clear(true); 3380b57cec5SDimitry Andric if (module_sp->ResolveSymbolContextForAddress( 3390b57cec5SDimitry Andric so_addr, eSymbolContextEverything, sc) & 3400b57cec5SDimitry Andric eSymbolContextLineEntry) { 3410b57cec5SDimitry Andric sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false); 3420b57cec5SDimitry Andric ++num_matches; 3430b57cec5SDimitry Andric } else { 3440b57cec5SDimitry Andric StreamString addr_strm; 3450b57cec5SDimitry Andric so_addr.Dump(&addr_strm, nullptr, 3460b57cec5SDimitry Andric Address::DumpStyleModuleWithFileAddress); 3470b57cec5SDimitry Andric error_strm.Printf( 3480b57cec5SDimitry Andric "Address 0x%" PRIx64 " resolves to %s, but there is" 3490b57cec5SDimitry Andric " no source information available for this address.\n", 3500b57cec5SDimitry Andric addr, addr_strm.GetData()); 3510b57cec5SDimitry Andric } 3520b57cec5SDimitry Andric } else { 3530b57cec5SDimitry Andric StreamString addr_strm; 3540b57cec5SDimitry Andric so_addr.Dump(&addr_strm, nullptr, 3550b57cec5SDimitry Andric Address::DumpStyleModuleWithFileAddress); 3560b57cec5SDimitry Andric error_strm.Printf("Address 0x%" PRIx64 3570b57cec5SDimitry Andric " resolves to %s, but it cannot" 3580b57cec5SDimitry Andric " be found in any modules.\n", 3590b57cec5SDimitry Andric addr, addr_strm.GetData()); 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric } else 3620b57cec5SDimitry Andric error_strm.Printf("Unable to resolve address 0x%" PRIx64 ".\n", addr); 3630b57cec5SDimitry Andric } 3640b57cec5SDimitry Andric return num_matches; 3650b57cec5SDimitry Andric } 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric // Dump the line entries found in functions matching the name specified in 3680b57cec5SDimitry Andric // the option. 3690b57cec5SDimitry Andric bool DumpLinesInFunctions(CommandReturnObject &result) { 3700b57cec5SDimitry Andric SymbolContextList sc_list_funcs; 3710b57cec5SDimitry Andric ConstString name(m_options.symbol_name.c_str()); 3720b57cec5SDimitry Andric SymbolContextList sc_list_lines; 3730b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 3740b57cec5SDimitry Andric uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); 3750b57cec5SDimitry Andric 376349cc55cSDimitry Andric ModuleFunctionSearchOptions function_options; 377349cc55cSDimitry Andric function_options.include_symbols = false; 378349cc55cSDimitry Andric function_options.include_inlines = true; 379349cc55cSDimitry Andric 3800b57cec5SDimitry Andric // Note: module_list can't be const& because FindFunctionSymbols isn't 3810b57cec5SDimitry Andric // const. 3820b57cec5SDimitry Andric ModuleList module_list = 3830b57cec5SDimitry Andric (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages(); 384349cc55cSDimitry Andric module_list.FindFunctions(name, eFunctionNameTypeAuto, function_options, 385349cc55cSDimitry Andric sc_list_funcs); 3869dba64beSDimitry Andric size_t num_matches = sc_list_funcs.GetSize(); 3879dba64beSDimitry Andric 3880b57cec5SDimitry Andric if (!num_matches) { 3890b57cec5SDimitry Andric // If we didn't find any functions with that name, try searching for 3900b57cec5SDimitry Andric // symbols that line up exactly with function addresses. 3910b57cec5SDimitry Andric SymbolContextList sc_list_symbols; 392480093f4SDimitry Andric module_list.FindFunctionSymbols(name, eFunctionNameTypeAuto, 393480093f4SDimitry Andric sc_list_symbols); 39406c3fb27SDimitry Andric for (const SymbolContext &sc : sc_list_symbols) { 3950b57cec5SDimitry Andric if (sc.symbol && sc.symbol->ValueIsAddress()) { 3960b57cec5SDimitry Andric const Address &base_address = sc.symbol->GetAddressRef(); 3970b57cec5SDimitry Andric Function *function = base_address.CalculateSymbolContextFunction(); 3980b57cec5SDimitry Andric if (function) { 3990b57cec5SDimitry Andric sc_list_funcs.Append(SymbolContext(function)); 4000b57cec5SDimitry Andric num_matches++; 4010b57cec5SDimitry Andric } 4020b57cec5SDimitry Andric } 4030b57cec5SDimitry Andric } 4040b57cec5SDimitry Andric } 4050b57cec5SDimitry Andric if (num_matches == 0) { 4060b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find function named \'%s\'.\n", 4070b57cec5SDimitry Andric m_options.symbol_name.c_str()); 4080b57cec5SDimitry Andric return false; 4090b57cec5SDimitry Andric } 41006c3fb27SDimitry Andric for (const SymbolContext &sc : sc_list_funcs) { 4110b57cec5SDimitry Andric bool context_found_for_symbol = false; 4120b57cec5SDimitry Andric // Loop through all the ranges in the function. 4130b57cec5SDimitry Andric AddressRange range; 4140b57cec5SDimitry Andric for (uint32_t r = 0; 4150b57cec5SDimitry Andric sc.GetAddressRange(eSymbolContextEverything, r, 4160b57cec5SDimitry Andric /*use_inline_block_range=*/true, range); 4170b57cec5SDimitry Andric ++r) { 4180b57cec5SDimitry Andric // Append the symbol contexts for each address in the range to 4190b57cec5SDimitry Andric // sc_list_lines. 4200b57cec5SDimitry Andric const Address &base_address = range.GetBaseAddress(); 4210b57cec5SDimitry Andric const addr_t size = range.GetByteSize(); 4220b57cec5SDimitry Andric lldb::addr_t start_addr = base_address.GetLoadAddress(target); 4230b57cec5SDimitry Andric if (start_addr == LLDB_INVALID_ADDRESS) 4240b57cec5SDimitry Andric start_addr = base_address.GetFileAddress(); 4250b57cec5SDimitry Andric lldb::addr_t end_addr = start_addr + size; 4260b57cec5SDimitry Andric for (lldb::addr_t addr = start_addr; addr < end_addr; 4270b57cec5SDimitry Andric addr += addr_byte_size) { 4280b57cec5SDimitry Andric StreamString error_strm; 4290b57cec5SDimitry Andric if (!GetSymbolContextsForAddress(module_list, addr, sc_list_lines, 4300b57cec5SDimitry Andric error_strm)) 4310b57cec5SDimitry Andric result.AppendWarningWithFormat("in symbol '%s': %s", 4320b57cec5SDimitry Andric sc.GetFunctionName().AsCString(), 4330b57cec5SDimitry Andric error_strm.GetData()); 4340b57cec5SDimitry Andric else 4350b57cec5SDimitry Andric context_found_for_symbol = true; 4360b57cec5SDimitry Andric } 4370b57cec5SDimitry Andric } 4380b57cec5SDimitry Andric if (!context_found_for_symbol) 4390b57cec5SDimitry Andric result.AppendWarningWithFormat("Unable to find line information" 4400b57cec5SDimitry Andric " for matching symbol '%s'.\n", 4410b57cec5SDimitry Andric sc.GetFunctionName().AsCString()); 4420b57cec5SDimitry Andric } 4430b57cec5SDimitry Andric if (sc_list_lines.GetSize() == 0) { 4440b57cec5SDimitry Andric result.AppendErrorWithFormat("No line information could be found" 4450b57cec5SDimitry Andric " for any symbols matching '%s'.\n", 4460b57cec5SDimitry Andric name.AsCString()); 4470b57cec5SDimitry Andric return false; 4480b57cec5SDimitry Andric } 4490b57cec5SDimitry Andric FileSpec file_spec; 4500b57cec5SDimitry Andric if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list_lines, 4510b57cec5SDimitry Andric module_list, file_spec)) { 4520b57cec5SDimitry Andric result.AppendErrorWithFormat( 4530b57cec5SDimitry Andric "Unable to dump line information for symbol '%s'.\n", 4540b57cec5SDimitry Andric name.AsCString()); 4550b57cec5SDimitry Andric return false; 4560b57cec5SDimitry Andric } 4570b57cec5SDimitry Andric return true; 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric 4600b57cec5SDimitry Andric // Dump the line entries found for the address specified in the option. 4610b57cec5SDimitry Andric bool DumpLinesForAddress(CommandReturnObject &result) { 4620b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 4630b57cec5SDimitry Andric SymbolContextList sc_list; 4640b57cec5SDimitry Andric 4650b57cec5SDimitry Andric StreamString error_strm; 4660b57cec5SDimitry Andric if (!GetSymbolContextsForAddress(target->GetImages(), m_options.address, 4670b57cec5SDimitry Andric sc_list, error_strm)) { 4680b57cec5SDimitry Andric result.AppendErrorWithFormat("%s.\n", error_strm.GetData()); 4690b57cec5SDimitry Andric return false; 4700b57cec5SDimitry Andric } 4710b57cec5SDimitry Andric ModuleList module_list; 4720b57cec5SDimitry Andric FileSpec file_spec; 4730b57cec5SDimitry Andric if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list, 4740b57cec5SDimitry Andric module_list, file_spec)) { 4750b57cec5SDimitry Andric result.AppendErrorWithFormat("No modules contain load address 0x%" PRIx64 4760b57cec5SDimitry Andric ".\n", 4770b57cec5SDimitry Andric m_options.address); 4780b57cec5SDimitry Andric return false; 4790b57cec5SDimitry Andric } 4800b57cec5SDimitry Andric return true; 4810b57cec5SDimitry Andric } 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric // Dump the line entries found in the file specified in the option. 4840b57cec5SDimitry Andric bool DumpLinesForFile(CommandReturnObject &result) { 4850b57cec5SDimitry Andric FileSpec file_spec(m_options.file_name); 4860b57cec5SDimitry Andric const char *filename = m_options.file_name.c_str(); 4870b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 4880b57cec5SDimitry Andric const ModuleList &module_list = 4890b57cec5SDimitry Andric (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages(); 4900b57cec5SDimitry Andric 4910b57cec5SDimitry Andric bool displayed_something = false; 4920b57cec5SDimitry Andric const size_t num_modules = module_list.GetSize(); 4930b57cec5SDimitry Andric for (uint32_t i = 0; i < num_modules; ++i) { 4940b57cec5SDimitry Andric // Dump lines for this module. 4950b57cec5SDimitry Andric Module *module = module_list.GetModulePointerAtIndex(i); 4960b57cec5SDimitry Andric assert(module); 4970b57cec5SDimitry Andric if (DumpFileLinesInModule(result.GetOutputStream(), module, file_spec)) 4980b57cec5SDimitry Andric displayed_something = true; 4990b57cec5SDimitry Andric } 5000b57cec5SDimitry Andric if (!displayed_something) { 5010b57cec5SDimitry Andric result.AppendErrorWithFormat("No source filenames matched '%s'.\n", 5020b57cec5SDimitry Andric filename); 5030b57cec5SDimitry Andric return false; 5040b57cec5SDimitry Andric } 5050b57cec5SDimitry Andric return true; 5060b57cec5SDimitry Andric } 5070b57cec5SDimitry Andric 5080b57cec5SDimitry Andric // Dump the line entries for the current frame. 5090b57cec5SDimitry Andric bool DumpLinesForFrame(CommandReturnObject &result) { 5100b57cec5SDimitry Andric StackFrame *cur_frame = m_exe_ctx.GetFramePtr(); 5110b57cec5SDimitry Andric if (cur_frame == nullptr) { 5120b57cec5SDimitry Andric result.AppendError( 5130b57cec5SDimitry Andric "No selected frame to use to find the default source."); 5140b57cec5SDimitry Andric return false; 5150b57cec5SDimitry Andric } else if (!cur_frame->HasDebugInformation()) { 5160b57cec5SDimitry Andric result.AppendError("No debug info for the selected frame."); 5170b57cec5SDimitry Andric return false; 5180b57cec5SDimitry Andric } else { 5190b57cec5SDimitry Andric const SymbolContext &sc = 5200b57cec5SDimitry Andric cur_frame->GetSymbolContext(eSymbolContextLineEntry); 5210b57cec5SDimitry Andric SymbolContextList sc_list; 5220b57cec5SDimitry Andric sc_list.Append(sc); 5230b57cec5SDimitry Andric ModuleList module_list; 5240b57cec5SDimitry Andric FileSpec file_spec; 5250b57cec5SDimitry Andric if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list, 5260b57cec5SDimitry Andric module_list, file_spec)) { 5270b57cec5SDimitry Andric result.AppendError( 5280b57cec5SDimitry Andric "No source line info available for the selected frame."); 5290b57cec5SDimitry Andric return false; 5300b57cec5SDimitry Andric } 5310b57cec5SDimitry Andric } 5320b57cec5SDimitry Andric return true; 5330b57cec5SDimitry Andric } 5340b57cec5SDimitry Andric 5355f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 5360b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 5370b57cec5SDimitry Andric if (target == nullptr) { 5380b57cec5SDimitry Andric target = GetDebugger().GetSelectedTarget().get(); 5390b57cec5SDimitry Andric if (target == nullptr) { 5400b57cec5SDimitry Andric result.AppendError("invalid target, create a debug target using the " 5410b57cec5SDimitry Andric "'target create' command."); 5425f757f3fSDimitry Andric return; 5430b57cec5SDimitry Andric } 5440b57cec5SDimitry Andric } 5450b57cec5SDimitry Andric 5460b57cec5SDimitry Andric uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); 5470b57cec5SDimitry Andric result.GetOutputStream().SetAddressByteSize(addr_byte_size); 5480b57cec5SDimitry Andric result.GetErrorStream().SetAddressByteSize(addr_byte_size); 5490b57cec5SDimitry Andric 5500b57cec5SDimitry Andric // Collect the list of modules to search. 5510b57cec5SDimitry Andric m_module_list.Clear(); 5520b57cec5SDimitry Andric if (!m_options.modules.empty()) { 5530b57cec5SDimitry Andric for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) { 5540b57cec5SDimitry Andric FileSpec module_file_spec(m_options.modules[i]); 5550b57cec5SDimitry Andric if (module_file_spec) { 5560b57cec5SDimitry Andric ModuleSpec module_spec(module_file_spec); 5579dba64beSDimitry Andric target->GetImages().FindModules(module_spec, m_module_list); 5589dba64beSDimitry Andric if (m_module_list.IsEmpty()) 5590b57cec5SDimitry Andric result.AppendWarningWithFormat("No module found for '%s'.\n", 5600b57cec5SDimitry Andric m_options.modules[i].c_str()); 5610b57cec5SDimitry Andric } 5620b57cec5SDimitry Andric } 5630b57cec5SDimitry Andric if (!m_module_list.GetSize()) { 5640b57cec5SDimitry Andric result.AppendError("No modules match the input."); 5655f757f3fSDimitry Andric return; 5660b57cec5SDimitry Andric } 5670b57cec5SDimitry Andric } else if (target->GetImages().GetSize() == 0) { 5680b57cec5SDimitry Andric result.AppendError("The target has no associated executable images."); 5695f757f3fSDimitry Andric return; 5700b57cec5SDimitry Andric } 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric // Check the arguments to see what lines we should dump. 5730b57cec5SDimitry Andric if (!m_options.symbol_name.empty()) { 5740b57cec5SDimitry Andric // Print lines for symbol. 5750b57cec5SDimitry Andric if (DumpLinesInFunctions(result)) 5760b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 5770b57cec5SDimitry Andric else 5780b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 5790b57cec5SDimitry Andric } else if (m_options.address != LLDB_INVALID_ADDRESS) { 5800b57cec5SDimitry Andric // Print lines for an address. 5810b57cec5SDimitry Andric if (DumpLinesForAddress(result)) 5820b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 5830b57cec5SDimitry Andric else 5840b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 5850b57cec5SDimitry Andric } else if (!m_options.file_name.empty()) { 5860b57cec5SDimitry Andric // Dump lines for a file. 5870b57cec5SDimitry Andric if (DumpLinesForFile(result)) 5880b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 5890b57cec5SDimitry Andric else 5900b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 5910b57cec5SDimitry Andric } else { 5920b57cec5SDimitry Andric // Dump the line for the current frame. 5930b57cec5SDimitry Andric if (DumpLinesForFrame(result)) 5940b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 5950b57cec5SDimitry Andric else 5960b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 5970b57cec5SDimitry Andric } 5980b57cec5SDimitry Andric } 5990b57cec5SDimitry Andric 6000b57cec5SDimitry Andric CommandOptions m_options; 6010b57cec5SDimitry Andric ModuleList m_module_list; 6020b57cec5SDimitry Andric }; 6030b57cec5SDimitry Andric 6040b57cec5SDimitry Andric #pragma mark CommandObjectSourceList 6050b57cec5SDimitry Andric // CommandObjectSourceList 6069dba64beSDimitry Andric #define LLDB_OPTIONS_source_list 6079dba64beSDimitry Andric #include "CommandOptions.inc" 6080b57cec5SDimitry Andric 6090b57cec5SDimitry Andric class CommandObjectSourceList : public CommandObjectParsed { 6100b57cec5SDimitry Andric class CommandOptions : public Options { 6110b57cec5SDimitry Andric public: 61281ad6265SDimitry Andric CommandOptions() = default; 6130b57cec5SDimitry Andric 6140b57cec5SDimitry Andric ~CommandOptions() override = default; 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 6170b57cec5SDimitry Andric ExecutionContext *execution_context) override { 6180b57cec5SDimitry Andric Status error; 6190b57cec5SDimitry Andric const int short_option = GetDefinitions()[option_idx].short_option; 6200b57cec5SDimitry Andric switch (short_option) { 6210b57cec5SDimitry Andric case 'l': 6220b57cec5SDimitry Andric if (option_arg.getAsInteger(0, start_line)) 6230b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line number: '%s'", 6240b57cec5SDimitry Andric option_arg.str().c_str()); 6250b57cec5SDimitry Andric break; 6260b57cec5SDimitry Andric 6270b57cec5SDimitry Andric case 'c': 6280b57cec5SDimitry Andric if (option_arg.getAsInteger(0, num_lines)) 6290b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line count: '%s'", 6300b57cec5SDimitry Andric option_arg.str().c_str()); 6310b57cec5SDimitry Andric break; 6320b57cec5SDimitry Andric 6330b57cec5SDimitry Andric case 'f': 6345ffd83dbSDimitry Andric file_name = std::string(option_arg); 6350b57cec5SDimitry Andric break; 6360b57cec5SDimitry Andric 6370b57cec5SDimitry Andric case 'n': 6385ffd83dbSDimitry Andric symbol_name = std::string(option_arg); 6390b57cec5SDimitry Andric break; 6400b57cec5SDimitry Andric 6410b57cec5SDimitry Andric case 'a': { 6420b57cec5SDimitry Andric address = OptionArgParser::ToAddress(execution_context, option_arg, 6430b57cec5SDimitry Andric LLDB_INVALID_ADDRESS, &error); 6440b57cec5SDimitry Andric } break; 6450b57cec5SDimitry Andric case 's': 6460b57cec5SDimitry Andric modules.push_back(std::string(option_arg)); 6470b57cec5SDimitry Andric break; 6480b57cec5SDimitry Andric 6490b57cec5SDimitry Andric case 'b': 6500b57cec5SDimitry Andric show_bp_locs = true; 6510b57cec5SDimitry Andric break; 6520b57cec5SDimitry Andric case 'r': 6530b57cec5SDimitry Andric reverse = true; 6540b57cec5SDimitry Andric break; 655e8d8bef9SDimitry Andric case 'y': 656e8d8bef9SDimitry Andric { 657e8d8bef9SDimitry Andric OptionValueFileColonLine value; 658e8d8bef9SDimitry Andric Status fcl_err = value.SetValueFromString(option_arg); 659e8d8bef9SDimitry Andric if (!fcl_err.Success()) { 660e8d8bef9SDimitry Andric error.SetErrorStringWithFormat( 661e8d8bef9SDimitry Andric "Invalid value for file:line specifier: %s", 662e8d8bef9SDimitry Andric fcl_err.AsCString()); 663e8d8bef9SDimitry Andric } else { 664e8d8bef9SDimitry Andric file_name = value.GetFileSpec().GetPath(); 665e8d8bef9SDimitry Andric start_line = value.GetLineNumber(); 666e8d8bef9SDimitry Andric // I don't see anything useful to do with a column number, but I don't 667e8d8bef9SDimitry Andric // want to complain since someone may well have cut and pasted a 668e8d8bef9SDimitry Andric // listing from somewhere that included a column. 669e8d8bef9SDimitry Andric } 670e8d8bef9SDimitry Andric } break; 6710b57cec5SDimitry Andric default: 6729dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 6730b57cec5SDimitry Andric } 6740b57cec5SDimitry Andric 6750b57cec5SDimitry Andric return error; 6760b57cec5SDimitry Andric } 6770b57cec5SDimitry Andric 6780b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 6790b57cec5SDimitry Andric file_spec.Clear(); 6800b57cec5SDimitry Andric file_name.clear(); 6810b57cec5SDimitry Andric symbol_name.clear(); 6820b57cec5SDimitry Andric address = LLDB_INVALID_ADDRESS; 6830b57cec5SDimitry Andric start_line = 0; 6840b57cec5SDimitry Andric num_lines = 0; 6850b57cec5SDimitry Andric show_bp_locs = false; 6860b57cec5SDimitry Andric reverse = false; 6870b57cec5SDimitry Andric modules.clear(); 6880b57cec5SDimitry Andric } 6890b57cec5SDimitry Andric 6900b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 691bdd1243dSDimitry Andric return llvm::ArrayRef(g_source_list_options); 6920b57cec5SDimitry Andric } 6930b57cec5SDimitry Andric 6940b57cec5SDimitry Andric // Instance variables to hold the values for command options. 6950b57cec5SDimitry Andric FileSpec file_spec; 6960b57cec5SDimitry Andric std::string file_name; 6970b57cec5SDimitry Andric std::string symbol_name; 6980b57cec5SDimitry Andric lldb::addr_t address; 6990b57cec5SDimitry Andric uint32_t start_line; 7000b57cec5SDimitry Andric uint32_t num_lines; 701480093f4SDimitry Andric std::vector<std::string> modules; 7020b57cec5SDimitry Andric bool show_bp_locs; 7030b57cec5SDimitry Andric bool reverse; 7040b57cec5SDimitry Andric }; 7050b57cec5SDimitry Andric 7060b57cec5SDimitry Andric public: 7070b57cec5SDimitry Andric CommandObjectSourceList(CommandInterpreter &interpreter) 7080b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "source list", 7090b57cec5SDimitry Andric "Display source code for the current target " 7100b57cec5SDimitry Andric "process as specified by options.", 71104eeddc0SDimitry Andric nullptr, eCommandRequiresTarget) {} 7120b57cec5SDimitry Andric 7130b57cec5SDimitry Andric ~CommandObjectSourceList() override = default; 7140b57cec5SDimitry Andric 7150b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 7160b57cec5SDimitry Andric 717bdd1243dSDimitry Andric std::optional<std::string> GetRepeatCommand(Args ¤t_command_args, 7180b57cec5SDimitry Andric uint32_t index) override { 7190b57cec5SDimitry Andric // This is kind of gross, but the command hasn't been parsed yet so we 7200b57cec5SDimitry Andric // can't look at the option values for this invocation... I have to scan 7210b57cec5SDimitry Andric // the arguments directly. 7220b57cec5SDimitry Andric auto iter = 7230b57cec5SDimitry Andric llvm::find_if(current_command_args, [](const Args::ArgEntry &e) { 7249dba64beSDimitry Andric return e.ref() == "-r" || e.ref() == "--reverse"; 7250b57cec5SDimitry Andric }); 7260b57cec5SDimitry Andric if (iter == current_command_args.end()) 72781ad6265SDimitry Andric return m_cmd_name; 7280b57cec5SDimitry Andric 7290b57cec5SDimitry Andric if (m_reverse_name.empty()) { 7300b57cec5SDimitry Andric m_reverse_name = m_cmd_name; 7310b57cec5SDimitry Andric m_reverse_name.append(" -r"); 7320b57cec5SDimitry Andric } 73381ad6265SDimitry Andric return m_reverse_name; 7340b57cec5SDimitry Andric } 7350b57cec5SDimitry Andric 7360b57cec5SDimitry Andric protected: 7370b57cec5SDimitry Andric struct SourceInfo { 7380b57cec5SDimitry Andric ConstString function; 7390b57cec5SDimitry Andric LineEntry line_entry; 7400b57cec5SDimitry Andric 7410b57cec5SDimitry Andric SourceInfo(ConstString name, const LineEntry &line_entry) 7420b57cec5SDimitry Andric : function(name), line_entry(line_entry) {} 7430b57cec5SDimitry Andric 74481ad6265SDimitry Andric SourceInfo() = default; 7450b57cec5SDimitry Andric 7460b57cec5SDimitry Andric bool IsValid() const { return (bool)function && line_entry.IsValid(); } 7470b57cec5SDimitry Andric 7480b57cec5SDimitry Andric bool operator==(const SourceInfo &rhs) const { 7490b57cec5SDimitry Andric return function == rhs.function && 750*0fca6ea1SDimitry Andric line_entry.original_file_sp->Equal( 751*0fca6ea1SDimitry Andric *rhs.line_entry.original_file_sp, 752*0fca6ea1SDimitry Andric SupportFile::eEqualFileSpecAndChecksumIfSet) && 7530b57cec5SDimitry Andric line_entry.line == rhs.line_entry.line; 7540b57cec5SDimitry Andric } 7550b57cec5SDimitry Andric 7560b57cec5SDimitry Andric bool operator!=(const SourceInfo &rhs) const { 7570b57cec5SDimitry Andric return function != rhs.function || 758*0fca6ea1SDimitry Andric !line_entry.original_file_sp->Equal( 759*0fca6ea1SDimitry Andric *rhs.line_entry.original_file_sp, 760*0fca6ea1SDimitry Andric SupportFile::eEqualFileSpecAndChecksumIfSet) || 7610b57cec5SDimitry Andric line_entry.line != rhs.line_entry.line; 7620b57cec5SDimitry Andric } 7630b57cec5SDimitry Andric 7640b57cec5SDimitry Andric bool operator<(const SourceInfo &rhs) const { 7650b57cec5SDimitry Andric if (function.GetCString() < rhs.function.GetCString()) 7660b57cec5SDimitry Andric return true; 767*0fca6ea1SDimitry Andric if (line_entry.GetFile().GetDirectory().GetCString() < 768*0fca6ea1SDimitry Andric rhs.line_entry.GetFile().GetDirectory().GetCString()) 7690b57cec5SDimitry Andric return true; 770*0fca6ea1SDimitry Andric if (line_entry.GetFile().GetFilename().GetCString() < 771*0fca6ea1SDimitry Andric rhs.line_entry.GetFile().GetFilename().GetCString()) 7720b57cec5SDimitry Andric return true; 7730b57cec5SDimitry Andric if (line_entry.line < rhs.line_entry.line) 7740b57cec5SDimitry Andric return true; 7750b57cec5SDimitry Andric return false; 7760b57cec5SDimitry Andric } 7770b57cec5SDimitry Andric }; 7780b57cec5SDimitry Andric 7790b57cec5SDimitry Andric size_t DisplayFunctionSource(const SymbolContext &sc, SourceInfo &source_info, 7800b57cec5SDimitry Andric CommandReturnObject &result) { 7810b57cec5SDimitry Andric if (!source_info.IsValid()) { 7820b57cec5SDimitry Andric source_info.function = sc.GetFunctionName(); 7830b57cec5SDimitry Andric source_info.line_entry = sc.GetFunctionStartLineEntry(); 7840b57cec5SDimitry Andric } 7850b57cec5SDimitry Andric 7860b57cec5SDimitry Andric if (sc.function) { 7870b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 7880b57cec5SDimitry Andric 7890b57cec5SDimitry Andric FileSpec start_file; 7900b57cec5SDimitry Andric uint32_t start_line; 7910b57cec5SDimitry Andric uint32_t end_line; 7920b57cec5SDimitry Andric FileSpec end_file; 7930b57cec5SDimitry Andric 7940b57cec5SDimitry Andric if (sc.block == nullptr) { 7950b57cec5SDimitry Andric // Not an inlined function 7960b57cec5SDimitry Andric sc.function->GetStartLineSourceInfo(start_file, start_line); 7970b57cec5SDimitry Andric if (start_line == 0) { 7980b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find line information for " 7990b57cec5SDimitry Andric "start of function: \"%s\".\n", 8000b57cec5SDimitry Andric source_info.function.GetCString()); 8010b57cec5SDimitry Andric return 0; 8020b57cec5SDimitry Andric } 8030b57cec5SDimitry Andric sc.function->GetEndLineSourceInfo(end_file, end_line); 8040b57cec5SDimitry Andric } else { 8050b57cec5SDimitry Andric // We have an inlined function 806*0fca6ea1SDimitry Andric start_file = source_info.line_entry.GetFile(); 8070b57cec5SDimitry Andric start_line = source_info.line_entry.line; 8080b57cec5SDimitry Andric end_line = start_line + m_options.num_lines; 8090b57cec5SDimitry Andric } 8100b57cec5SDimitry Andric 8110b57cec5SDimitry Andric // This is a little hacky, but the first line table entry for a function 8120b57cec5SDimitry Andric // points to the "{" that starts the function block. It would be nice to 8130b57cec5SDimitry Andric // actually get the function declaration in there too. So back up a bit, 8140b57cec5SDimitry Andric // but not further than what you're going to display. 8150b57cec5SDimitry Andric uint32_t extra_lines; 8160b57cec5SDimitry Andric if (m_options.num_lines >= 10) 8170b57cec5SDimitry Andric extra_lines = 5; 8180b57cec5SDimitry Andric else 8190b57cec5SDimitry Andric extra_lines = m_options.num_lines / 2; 8200b57cec5SDimitry Andric uint32_t line_no; 8210b57cec5SDimitry Andric if (start_line <= extra_lines) 8220b57cec5SDimitry Andric line_no = 1; 8230b57cec5SDimitry Andric else 8240b57cec5SDimitry Andric line_no = start_line - extra_lines; 8250b57cec5SDimitry Andric 8260b57cec5SDimitry Andric // For fun, if the function is shorter than the number of lines we're 8270b57cec5SDimitry Andric // supposed to display, only display the function... 8280b57cec5SDimitry Andric if (end_line != 0) { 8290b57cec5SDimitry Andric if (m_options.num_lines > end_line - line_no) 8300b57cec5SDimitry Andric m_options.num_lines = end_line - line_no + extra_lines; 8310b57cec5SDimitry Andric } 8320b57cec5SDimitry Andric 8330b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 8340b57cec5SDimitry Andric 8350b57cec5SDimitry Andric if (m_options.show_bp_locs) { 8360b57cec5SDimitry Andric const bool show_inlines = true; 8370b57cec5SDimitry Andric m_breakpoint_locations.Reset(start_file, 0, show_inlines); 8380b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 8390b57cec5SDimitry Andric m_exe_ctx.GetTargetSP()); 8400b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 8410b57cec5SDimitry Andric } 8420b57cec5SDimitry Andric 8430b57cec5SDimitry Andric result.AppendMessageWithFormat("File: %s\n", 8440b57cec5SDimitry Andric start_file.GetPath().c_str()); 8450b57cec5SDimitry Andric // We don't care about the column here. 8460b57cec5SDimitry Andric const uint32_t column = 0; 8470b57cec5SDimitry Andric return target->GetSourceManager().DisplaySourceLinesWithLineNumbers( 8480b57cec5SDimitry Andric start_file, line_no, column, 0, m_options.num_lines, "", 8490b57cec5SDimitry Andric &result.GetOutputStream(), GetBreakpointLocations()); 8500b57cec5SDimitry Andric } else { 8510b57cec5SDimitry Andric result.AppendErrorWithFormat( 8520b57cec5SDimitry Andric "Could not find function info for: \"%s\".\n", 8530b57cec5SDimitry Andric m_options.symbol_name.c_str()); 8540b57cec5SDimitry Andric } 8550b57cec5SDimitry Andric return 0; 8560b57cec5SDimitry Andric } 8570b57cec5SDimitry Andric 8580b57cec5SDimitry Andric // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols 8590b57cec5SDimitry Andric // functions "take a possibly empty vector of strings which are names of 8600b57cec5SDimitry Andric // modules, and run the two search functions on the subset of the full module 8610b57cec5SDimitry Andric // list that matches the strings in the input vector". If we wanted to put 8620b57cec5SDimitry Andric // these somewhere, there should probably be a module-filter-list that can be 8630b57cec5SDimitry Andric // passed to the various ModuleList::Find* calls, which would either be a 8640b57cec5SDimitry Andric // vector of string names or a ModuleSpecList. 8659dba64beSDimitry Andric void FindMatchingFunctions(Target *target, ConstString name, 8660b57cec5SDimitry Andric SymbolContextList &sc_list) { 8670b57cec5SDimitry Andric // Displaying the source for a symbol: 8680b57cec5SDimitry Andric if (m_options.num_lines == 0) 8690b57cec5SDimitry Andric m_options.num_lines = 10; 8700b57cec5SDimitry Andric 871349cc55cSDimitry Andric ModuleFunctionSearchOptions function_options; 872349cc55cSDimitry Andric function_options.include_symbols = true; 873349cc55cSDimitry Andric function_options.include_inlines = false; 874349cc55cSDimitry Andric 8750b57cec5SDimitry Andric const size_t num_modules = m_options.modules.size(); 8760b57cec5SDimitry Andric if (num_modules > 0) { 8770b57cec5SDimitry Andric ModuleList matching_modules; 8780b57cec5SDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 8790b57cec5SDimitry Andric FileSpec module_file_spec(m_options.modules[i]); 8800b57cec5SDimitry Andric if (module_file_spec) { 8810b57cec5SDimitry Andric ModuleSpec module_spec(module_file_spec); 8820b57cec5SDimitry Andric matching_modules.Clear(); 8830b57cec5SDimitry Andric target->GetImages().FindModules(module_spec, matching_modules); 884349cc55cSDimitry Andric 885480093f4SDimitry Andric matching_modules.FindFunctions(name, eFunctionNameTypeAuto, 886349cc55cSDimitry Andric function_options, sc_list); 8870b57cec5SDimitry Andric } 8880b57cec5SDimitry Andric } 8890b57cec5SDimitry Andric } else { 8909dba64beSDimitry Andric target->GetImages().FindFunctions(name, eFunctionNameTypeAuto, 891349cc55cSDimitry Andric function_options, sc_list); 8920b57cec5SDimitry Andric } 8930b57cec5SDimitry Andric } 8940b57cec5SDimitry Andric 8959dba64beSDimitry Andric void FindMatchingFunctionSymbols(Target *target, ConstString name, 8960b57cec5SDimitry Andric SymbolContextList &sc_list) { 8970b57cec5SDimitry Andric const size_t num_modules = m_options.modules.size(); 8980b57cec5SDimitry Andric if (num_modules > 0) { 8990b57cec5SDimitry Andric ModuleList matching_modules; 9000b57cec5SDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 9010b57cec5SDimitry Andric FileSpec module_file_spec(m_options.modules[i]); 9020b57cec5SDimitry Andric if (module_file_spec) { 9030b57cec5SDimitry Andric ModuleSpec module_spec(module_file_spec); 9040b57cec5SDimitry Andric matching_modules.Clear(); 9050b57cec5SDimitry Andric target->GetImages().FindModules(module_spec, matching_modules); 9069dba64beSDimitry Andric matching_modules.FindFunctionSymbols(name, eFunctionNameTypeAuto, 9079dba64beSDimitry Andric sc_list); 9080b57cec5SDimitry Andric } 9090b57cec5SDimitry Andric } 9100b57cec5SDimitry Andric } else { 9119dba64beSDimitry Andric target->GetImages().FindFunctionSymbols(name, eFunctionNameTypeAuto, 9129dba64beSDimitry Andric sc_list); 9130b57cec5SDimitry Andric } 9140b57cec5SDimitry Andric } 9150b57cec5SDimitry Andric 9165f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 9170b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 9180b57cec5SDimitry Andric 9190b57cec5SDimitry Andric if (!m_options.symbol_name.empty()) { 9200b57cec5SDimitry Andric SymbolContextList sc_list; 9210b57cec5SDimitry Andric ConstString name(m_options.symbol_name.c_str()); 9220b57cec5SDimitry Andric 9230b57cec5SDimitry Andric // Displaying the source for a symbol. Search for function named name. 9249dba64beSDimitry Andric FindMatchingFunctions(target, name, sc_list); 92506c3fb27SDimitry Andric if (sc_list.GetSize() == 0) { 9260b57cec5SDimitry Andric // If we didn't find any functions with that name, try searching for 9270b57cec5SDimitry Andric // symbols that line up exactly with function addresses. 9280b57cec5SDimitry Andric SymbolContextList sc_list_symbols; 9290b57cec5SDimitry Andric FindMatchingFunctionSymbols(target, name, sc_list_symbols); 93006c3fb27SDimitry Andric for (const SymbolContext &sc : sc_list_symbols) { 9310b57cec5SDimitry Andric if (sc.symbol && sc.symbol->ValueIsAddress()) { 9320b57cec5SDimitry Andric const Address &base_address = sc.symbol->GetAddressRef(); 9330b57cec5SDimitry Andric Function *function = base_address.CalculateSymbolContextFunction(); 9340b57cec5SDimitry Andric if (function) { 9350b57cec5SDimitry Andric sc_list.Append(SymbolContext(function)); 9360b57cec5SDimitry Andric break; 9370b57cec5SDimitry Andric } 9380b57cec5SDimitry Andric } 9390b57cec5SDimitry Andric } 9400b57cec5SDimitry Andric } 9410b57cec5SDimitry Andric 94206c3fb27SDimitry Andric if (sc_list.GetSize() == 0) { 9430b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find function named: \"%s\".\n", 9440b57cec5SDimitry Andric m_options.symbol_name.c_str()); 9455f757f3fSDimitry Andric return; 9460b57cec5SDimitry Andric } 9470b57cec5SDimitry Andric 9480b57cec5SDimitry Andric std::set<SourceInfo> source_match_set; 9490b57cec5SDimitry Andric bool displayed_something = false; 95006c3fb27SDimitry Andric for (const SymbolContext &sc : sc_list) { 9510b57cec5SDimitry Andric SourceInfo source_info(sc.GetFunctionName(), 9520b57cec5SDimitry Andric sc.GetFunctionStartLineEntry()); 95306c3fb27SDimitry Andric if (source_info.IsValid() && 95406c3fb27SDimitry Andric source_match_set.find(source_info) == source_match_set.end()) { 9550b57cec5SDimitry Andric source_match_set.insert(source_info); 9560b57cec5SDimitry Andric if (DisplayFunctionSource(sc, source_info, result)) 9570b57cec5SDimitry Andric displayed_something = true; 9580b57cec5SDimitry Andric } 9590b57cec5SDimitry Andric } 9600b57cec5SDimitry Andric if (displayed_something) 9610b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 9620b57cec5SDimitry Andric else 9630b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 9645f757f3fSDimitry Andric return; 9650b57cec5SDimitry Andric } else if (m_options.address != LLDB_INVALID_ADDRESS) { 9660b57cec5SDimitry Andric Address so_addr; 9670b57cec5SDimitry Andric StreamString error_strm; 9680b57cec5SDimitry Andric SymbolContextList sc_list; 9690b57cec5SDimitry Andric 9700b57cec5SDimitry Andric if (target->GetSectionLoadList().IsEmpty()) { 9710b57cec5SDimitry Andric // The target isn't loaded yet, we need to lookup the file address in 9720b57cec5SDimitry Andric // all modules 9730b57cec5SDimitry Andric const ModuleList &module_list = target->GetImages(); 9740b57cec5SDimitry Andric const size_t num_modules = module_list.GetSize(); 9750b57cec5SDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 9760b57cec5SDimitry Andric ModuleSP module_sp(module_list.GetModuleAtIndex(i)); 9770b57cec5SDimitry Andric if (module_sp && 9780b57cec5SDimitry Andric module_sp->ResolveFileAddress(m_options.address, so_addr)) { 9790b57cec5SDimitry Andric SymbolContext sc; 9800b57cec5SDimitry Andric sc.Clear(true); 9810b57cec5SDimitry Andric if (module_sp->ResolveSymbolContextForAddress( 9820b57cec5SDimitry Andric so_addr, eSymbolContextEverything, sc) & 9830b57cec5SDimitry Andric eSymbolContextLineEntry) 9840b57cec5SDimitry Andric sc_list.Append(sc); 9850b57cec5SDimitry Andric } 9860b57cec5SDimitry Andric } 9870b57cec5SDimitry Andric 9880b57cec5SDimitry Andric if (sc_list.GetSize() == 0) { 9890b57cec5SDimitry Andric result.AppendErrorWithFormat( 9900b57cec5SDimitry Andric "no modules have source information for file address 0x%" PRIx64 9910b57cec5SDimitry Andric ".\n", 9920b57cec5SDimitry Andric m_options.address); 9935f757f3fSDimitry Andric return; 9940b57cec5SDimitry Andric } 9950b57cec5SDimitry Andric } else { 9960b57cec5SDimitry Andric // The target has some things loaded, resolve this address to a compile 9970b57cec5SDimitry Andric // unit + file + line and display 9980b57cec5SDimitry Andric if (target->GetSectionLoadList().ResolveLoadAddress(m_options.address, 9990b57cec5SDimitry Andric so_addr)) { 10000b57cec5SDimitry Andric ModuleSP module_sp(so_addr.GetModule()); 10010b57cec5SDimitry Andric if (module_sp) { 10020b57cec5SDimitry Andric SymbolContext sc; 10030b57cec5SDimitry Andric sc.Clear(true); 10040b57cec5SDimitry Andric if (module_sp->ResolveSymbolContextForAddress( 10050b57cec5SDimitry Andric so_addr, eSymbolContextEverything, sc) & 10060b57cec5SDimitry Andric eSymbolContextLineEntry) { 10070b57cec5SDimitry Andric sc_list.Append(sc); 10080b57cec5SDimitry Andric } else { 10090b57cec5SDimitry Andric so_addr.Dump(&error_strm, nullptr, 10100b57cec5SDimitry Andric Address::DumpStyleModuleWithFileAddress); 10110b57cec5SDimitry Andric result.AppendErrorWithFormat("address resolves to %s, but there " 10120b57cec5SDimitry Andric "is no line table information " 10130b57cec5SDimitry Andric "available for this address.\n", 10140b57cec5SDimitry Andric error_strm.GetData()); 10155f757f3fSDimitry Andric return; 10160b57cec5SDimitry Andric } 10170b57cec5SDimitry Andric } 10180b57cec5SDimitry Andric } 10190b57cec5SDimitry Andric 10200b57cec5SDimitry Andric if (sc_list.GetSize() == 0) { 10210b57cec5SDimitry Andric result.AppendErrorWithFormat( 10220b57cec5SDimitry Andric "no modules contain load address 0x%" PRIx64 ".\n", 10230b57cec5SDimitry Andric m_options.address); 10245f757f3fSDimitry Andric return; 10250b57cec5SDimitry Andric } 10260b57cec5SDimitry Andric } 102706c3fb27SDimitry Andric for (const SymbolContext &sc : sc_list) { 10280b57cec5SDimitry Andric if (sc.comp_unit) { 10290b57cec5SDimitry Andric if (m_options.show_bp_locs) { 10300b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 10310b57cec5SDimitry Andric const bool show_inlines = true; 1032480093f4SDimitry Andric m_breakpoint_locations.Reset(sc.comp_unit->GetPrimaryFile(), 0, 1033480093f4SDimitry Andric show_inlines); 10340b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 10350b57cec5SDimitry Andric target->shared_from_this()); 10360b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 10370b57cec5SDimitry Andric } 10380b57cec5SDimitry Andric 10390b57cec5SDimitry Andric bool show_fullpaths = true; 10400b57cec5SDimitry Andric bool show_module = true; 10410b57cec5SDimitry Andric bool show_inlined_frames = true; 10420b57cec5SDimitry Andric const bool show_function_arguments = true; 10430b57cec5SDimitry Andric const bool show_function_name = true; 10440b57cec5SDimitry Andric sc.DumpStopContext(&result.GetOutputStream(), 10450b57cec5SDimitry Andric m_exe_ctx.GetBestExecutionContextScope(), 10460b57cec5SDimitry Andric sc.line_entry.range.GetBaseAddress(), 10470b57cec5SDimitry Andric show_fullpaths, show_module, show_inlined_frames, 10480b57cec5SDimitry Andric show_function_arguments, show_function_name); 10490b57cec5SDimitry Andric result.GetOutputStream().EOL(); 10500b57cec5SDimitry Andric 10510b57cec5SDimitry Andric if (m_options.num_lines == 0) 10520b57cec5SDimitry Andric m_options.num_lines = 10; 10530b57cec5SDimitry Andric 10540b57cec5SDimitry Andric size_t lines_to_back_up = 10550b57cec5SDimitry Andric m_options.num_lines >= 10 ? 5 : m_options.num_lines / 2; 10560b57cec5SDimitry Andric 10570b57cec5SDimitry Andric const uint32_t column = 10580b57cec5SDimitry Andric (GetDebugger().GetStopShowColumn() != eStopShowColumnNone) 10590b57cec5SDimitry Andric ? sc.line_entry.column 10600b57cec5SDimitry Andric : 0; 10610b57cec5SDimitry Andric target->GetSourceManager().DisplaySourceLinesWithLineNumbers( 1062480093f4SDimitry Andric sc.comp_unit->GetPrimaryFile(), sc.line_entry.line, column, 1063480093f4SDimitry Andric lines_to_back_up, m_options.num_lines - lines_to_back_up, "->", 10640b57cec5SDimitry Andric &result.GetOutputStream(), GetBreakpointLocations()); 10650b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 10660b57cec5SDimitry Andric } 10670b57cec5SDimitry Andric } 10680b57cec5SDimitry Andric } else if (m_options.file_name.empty()) { 10690b57cec5SDimitry Andric // Last valid source manager context, or the current frame if no valid 10700b57cec5SDimitry Andric // last context in source manager. One little trick here, if you type the 10710b57cec5SDimitry Andric // exact same list command twice in a row, it is more likely because you 10720b57cec5SDimitry Andric // typed it once, then typed it again 10730b57cec5SDimitry Andric if (m_options.start_line == 0) { 10740b57cec5SDimitry Andric if (target->GetSourceManager().DisplayMoreWithLineNumbers( 10750b57cec5SDimitry Andric &result.GetOutputStream(), m_options.num_lines, 10760b57cec5SDimitry Andric m_options.reverse, GetBreakpointLocations())) { 10770b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 10780b57cec5SDimitry Andric } 10790b57cec5SDimitry Andric } else { 10800b57cec5SDimitry Andric if (m_options.num_lines == 0) 10810b57cec5SDimitry Andric m_options.num_lines = 10; 10820b57cec5SDimitry Andric 10830b57cec5SDimitry Andric if (m_options.show_bp_locs) { 10840b57cec5SDimitry Andric SourceManager::FileSP last_file_sp( 10850b57cec5SDimitry Andric target->GetSourceManager().GetLastFile()); 10860b57cec5SDimitry Andric if (last_file_sp) { 10870b57cec5SDimitry Andric const bool show_inlines = true; 10880b57cec5SDimitry Andric m_breakpoint_locations.Reset(last_file_sp->GetFileSpec(), 0, 10890b57cec5SDimitry Andric show_inlines); 10900b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 10910b57cec5SDimitry Andric target->shared_from_this()); 10920b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 10930b57cec5SDimitry Andric } 10940b57cec5SDimitry Andric } else 10950b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 10960b57cec5SDimitry Andric 10970b57cec5SDimitry Andric const uint32_t column = 0; 10980b57cec5SDimitry Andric if (target->GetSourceManager() 10990b57cec5SDimitry Andric .DisplaySourceLinesWithLineNumbersUsingLastFile( 11000b57cec5SDimitry Andric m_options.start_line, // Line to display 11010b57cec5SDimitry Andric m_options.num_lines, // Lines after line to 11020b57cec5SDimitry Andric UINT32_MAX, // Don't mark "line" 11030b57cec5SDimitry Andric column, 11040b57cec5SDimitry Andric "", // Don't mark "line" 11050b57cec5SDimitry Andric &result.GetOutputStream(), GetBreakpointLocations())) { 11060b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 11070b57cec5SDimitry Andric } 11080b57cec5SDimitry Andric } 11090b57cec5SDimitry Andric } else { 11100b57cec5SDimitry Andric const char *filename = m_options.file_name.c_str(); 11110b57cec5SDimitry Andric 11120b57cec5SDimitry Andric bool check_inlines = false; 11130b57cec5SDimitry Andric SymbolContextList sc_list; 11140b57cec5SDimitry Andric size_t num_matches = 0; 11150b57cec5SDimitry Andric 11160b57cec5SDimitry Andric if (!m_options.modules.empty()) { 11170b57cec5SDimitry Andric ModuleList matching_modules; 11180b57cec5SDimitry Andric for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) { 11190b57cec5SDimitry Andric FileSpec module_file_spec(m_options.modules[i]); 11200b57cec5SDimitry Andric if (module_file_spec) { 11210b57cec5SDimitry Andric ModuleSpec module_spec(module_file_spec); 11220b57cec5SDimitry Andric matching_modules.Clear(); 11230b57cec5SDimitry Andric target->GetImages().FindModules(module_spec, matching_modules); 11240b57cec5SDimitry Andric num_matches += matching_modules.ResolveSymbolContextForFilePath( 11250b57cec5SDimitry Andric filename, 0, check_inlines, 11260b57cec5SDimitry Andric SymbolContextItem(eSymbolContextModule | 11270b57cec5SDimitry Andric eSymbolContextCompUnit), 11280b57cec5SDimitry Andric sc_list); 11290b57cec5SDimitry Andric } 11300b57cec5SDimitry Andric } 11310b57cec5SDimitry Andric } else { 11320b57cec5SDimitry Andric num_matches = target->GetImages().ResolveSymbolContextForFilePath( 11330b57cec5SDimitry Andric filename, 0, check_inlines, 11340b57cec5SDimitry Andric eSymbolContextModule | eSymbolContextCompUnit, sc_list); 11350b57cec5SDimitry Andric } 11360b57cec5SDimitry Andric 11370b57cec5SDimitry Andric if (num_matches == 0) { 11380b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find source file \"%s\".\n", 11390b57cec5SDimitry Andric m_options.file_name.c_str()); 11405f757f3fSDimitry Andric return; 11410b57cec5SDimitry Andric } 11420b57cec5SDimitry Andric 11430b57cec5SDimitry Andric if (num_matches > 1) { 11440b57cec5SDimitry Andric bool got_multiple = false; 1145480093f4SDimitry Andric CompileUnit *test_cu = nullptr; 11460b57cec5SDimitry Andric 114706c3fb27SDimitry Andric for (const SymbolContext &sc : sc_list) { 11480b57cec5SDimitry Andric if (sc.comp_unit) { 1149480093f4SDimitry Andric if (test_cu) { 1150480093f4SDimitry Andric if (test_cu != sc.comp_unit) 11510b57cec5SDimitry Andric got_multiple = true; 11520b57cec5SDimitry Andric break; 11530b57cec5SDimitry Andric } else 1154480093f4SDimitry Andric test_cu = sc.comp_unit; 11550b57cec5SDimitry Andric } 11560b57cec5SDimitry Andric } 11570b57cec5SDimitry Andric if (got_multiple) { 11580b57cec5SDimitry Andric result.AppendErrorWithFormat( 11590b57cec5SDimitry Andric "Multiple source files found matching: \"%s.\"\n", 11600b57cec5SDimitry Andric m_options.file_name.c_str()); 11615f757f3fSDimitry Andric return; 11620b57cec5SDimitry Andric } 11630b57cec5SDimitry Andric } 11640b57cec5SDimitry Andric 11650b57cec5SDimitry Andric SymbolContext sc; 11660b57cec5SDimitry Andric if (sc_list.GetContextAtIndex(0, sc)) { 11670b57cec5SDimitry Andric if (sc.comp_unit) { 11680b57cec5SDimitry Andric if (m_options.show_bp_locs) { 11690b57cec5SDimitry Andric const bool show_inlines = true; 1170480093f4SDimitry Andric m_breakpoint_locations.Reset(sc.comp_unit->GetPrimaryFile(), 0, 1171480093f4SDimitry Andric show_inlines); 11720b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 11730b57cec5SDimitry Andric target->shared_from_this()); 11740b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 11750b57cec5SDimitry Andric } else 11760b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 11770b57cec5SDimitry Andric 11780b57cec5SDimitry Andric if (m_options.num_lines == 0) 11790b57cec5SDimitry Andric m_options.num_lines = 10; 11800b57cec5SDimitry Andric const uint32_t column = 0; 11810b57cec5SDimitry Andric target->GetSourceManager().DisplaySourceLinesWithLineNumbers( 1182480093f4SDimitry Andric sc.comp_unit->GetPrimaryFile(), m_options.start_line, column, 0, 1183480093f4SDimitry Andric m_options.num_lines, "", &result.GetOutputStream(), 1184480093f4SDimitry Andric GetBreakpointLocations()); 11850b57cec5SDimitry Andric 11860b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 11870b57cec5SDimitry Andric } else { 11880b57cec5SDimitry Andric result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n", 11890b57cec5SDimitry Andric m_options.file_name.c_str()); 11900b57cec5SDimitry Andric } 11910b57cec5SDimitry Andric } 11920b57cec5SDimitry Andric } 11930b57cec5SDimitry Andric } 11940b57cec5SDimitry Andric 11950b57cec5SDimitry Andric const SymbolContextList *GetBreakpointLocations() { 11960b57cec5SDimitry Andric if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0) 11970b57cec5SDimitry Andric return &m_breakpoint_locations.GetFileLineMatches(); 11980b57cec5SDimitry Andric return nullptr; 11990b57cec5SDimitry Andric } 12000b57cec5SDimitry Andric 12010b57cec5SDimitry Andric CommandOptions m_options; 12020b57cec5SDimitry Andric FileLineResolver m_breakpoint_locations; 12030b57cec5SDimitry Andric std::string m_reverse_name; 12040b57cec5SDimitry Andric }; 12050b57cec5SDimitry Andric 120606c3fb27SDimitry Andric class CommandObjectSourceCacheDump : public CommandObjectParsed { 120706c3fb27SDimitry Andric public: 120806c3fb27SDimitry Andric CommandObjectSourceCacheDump(CommandInterpreter &interpreter) 120906c3fb27SDimitry Andric : CommandObjectParsed(interpreter, "source cache dump", 121006c3fb27SDimitry Andric "Dump the state of the source code cache. Intended " 121106c3fb27SDimitry Andric "to be used for debugging LLDB itself.", 121206c3fb27SDimitry Andric nullptr) {} 121306c3fb27SDimitry Andric 121406c3fb27SDimitry Andric ~CommandObjectSourceCacheDump() override = default; 121506c3fb27SDimitry Andric 121606c3fb27SDimitry Andric protected: 12175f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 121806c3fb27SDimitry Andric // Dump the debugger source cache. 121906c3fb27SDimitry Andric result.GetOutputStream() << "Debugger Source File Cache\n"; 122006c3fb27SDimitry Andric SourceManager::SourceFileCache &cache = GetDebugger().GetSourceFileCache(); 122106c3fb27SDimitry Andric cache.Dump(result.GetOutputStream()); 122206c3fb27SDimitry Andric 122306c3fb27SDimitry Andric // Dump the process source cache. 122406c3fb27SDimitry Andric if (ProcessSP process_sp = m_exe_ctx.GetProcessSP()) { 122506c3fb27SDimitry Andric result.GetOutputStream() << "\nProcess Source File Cache\n"; 122606c3fb27SDimitry Andric SourceManager::SourceFileCache &cache = process_sp->GetSourceFileCache(); 122706c3fb27SDimitry Andric cache.Dump(result.GetOutputStream()); 122806c3fb27SDimitry Andric } 122906c3fb27SDimitry Andric 123006c3fb27SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 123106c3fb27SDimitry Andric } 123206c3fb27SDimitry Andric }; 123306c3fb27SDimitry Andric 123406c3fb27SDimitry Andric class CommandObjectSourceCacheClear : public CommandObjectParsed { 123506c3fb27SDimitry Andric public: 123606c3fb27SDimitry Andric CommandObjectSourceCacheClear(CommandInterpreter &interpreter) 123706c3fb27SDimitry Andric : CommandObjectParsed(interpreter, "source cache clear", 123806c3fb27SDimitry Andric "Clear the source code cache.\n", nullptr) {} 123906c3fb27SDimitry Andric 124006c3fb27SDimitry Andric ~CommandObjectSourceCacheClear() override = default; 124106c3fb27SDimitry Andric 124206c3fb27SDimitry Andric protected: 12435f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 124406c3fb27SDimitry Andric // Clear the debugger cache. 124506c3fb27SDimitry Andric SourceManager::SourceFileCache &cache = GetDebugger().GetSourceFileCache(); 124606c3fb27SDimitry Andric cache.Clear(); 124706c3fb27SDimitry Andric 124806c3fb27SDimitry Andric // Clear the process cache. 124906c3fb27SDimitry Andric if (ProcessSP process_sp = m_exe_ctx.GetProcessSP()) 125006c3fb27SDimitry Andric process_sp->GetSourceFileCache().Clear(); 125106c3fb27SDimitry Andric 125206c3fb27SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 125306c3fb27SDimitry Andric } 125406c3fb27SDimitry Andric }; 125506c3fb27SDimitry Andric 125606c3fb27SDimitry Andric class CommandObjectSourceCache : public CommandObjectMultiword { 125706c3fb27SDimitry Andric public: 125806c3fb27SDimitry Andric CommandObjectSourceCache(CommandInterpreter &interpreter) 125906c3fb27SDimitry Andric : CommandObjectMultiword(interpreter, "source cache", 126006c3fb27SDimitry Andric "Commands for managing the source code cache.", 126106c3fb27SDimitry Andric "source cache <sub-command>") { 126206c3fb27SDimitry Andric LoadSubCommand( 126306c3fb27SDimitry Andric "dump", CommandObjectSP(new CommandObjectSourceCacheDump(interpreter))); 126406c3fb27SDimitry Andric LoadSubCommand("clear", CommandObjectSP(new CommandObjectSourceCacheClear( 126506c3fb27SDimitry Andric interpreter))); 126606c3fb27SDimitry Andric } 126706c3fb27SDimitry Andric 126806c3fb27SDimitry Andric ~CommandObjectSourceCache() override = default; 126906c3fb27SDimitry Andric 127006c3fb27SDimitry Andric private: 127106c3fb27SDimitry Andric CommandObjectSourceCache(const CommandObjectSourceCache &) = delete; 127206c3fb27SDimitry Andric const CommandObjectSourceCache & 127306c3fb27SDimitry Andric operator=(const CommandObjectSourceCache &) = delete; 127406c3fb27SDimitry Andric }; 127506c3fb27SDimitry Andric 12760b57cec5SDimitry Andric #pragma mark CommandObjectMultiwordSource 12770b57cec5SDimitry Andric // CommandObjectMultiwordSource 12780b57cec5SDimitry Andric 12790b57cec5SDimitry Andric CommandObjectMultiwordSource::CommandObjectMultiwordSource( 12800b57cec5SDimitry Andric CommandInterpreter &interpreter) 1281480093f4SDimitry Andric : CommandObjectMultiword(interpreter, "source", 1282480093f4SDimitry Andric "Commands for examining " 12830b57cec5SDimitry Andric "source code described by " 12840b57cec5SDimitry Andric "debug information for the " 12850b57cec5SDimitry Andric "current target process.", 12860b57cec5SDimitry Andric "source <subcommand> [<subcommand-options>]") { 12870b57cec5SDimitry Andric LoadSubCommand("info", 12880b57cec5SDimitry Andric CommandObjectSP(new CommandObjectSourceInfo(interpreter))); 12890b57cec5SDimitry Andric LoadSubCommand("list", 12900b57cec5SDimitry Andric CommandObjectSP(new CommandObjectSourceList(interpreter))); 129106c3fb27SDimitry Andric LoadSubCommand("cache", 129206c3fb27SDimitry Andric CommandObjectSP(new CommandObjectSourceCache(interpreter))); 12930b57cec5SDimitry Andric } 12940b57cec5SDimitry Andric 12950b57cec5SDimitry Andric CommandObjectMultiwordSource::~CommandObjectMultiwordSource() = default; 1296