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" 25*fe013be4SDimitry 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; 150*fe013be4SDimitry 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; 161480093f4SDimitry Andric if (!FileSpec::Match(file_spec, line_entry.file)) 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); 2070b57cec5SDimitry Andric const FileSpecList &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; 242480093f4SDimitry Andric assert(cu_file_spec == line_entry.file); 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); 394*fe013be4SDimitry 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 } 410*fe013be4SDimitry 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 5350b57cec5SDimitry Andric bool 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."); 5420b57cec5SDimitry Andric return false; 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."); 5650b57cec5SDimitry Andric return false; 5660b57cec5SDimitry Andric } 5670b57cec5SDimitry Andric } else if (target->GetImages().GetSize() == 0) { 5680b57cec5SDimitry Andric result.AppendError("The target has no associated executable images."); 5690b57cec5SDimitry Andric return false; 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 return result.Succeeded(); 5990b57cec5SDimitry Andric } 6000b57cec5SDimitry Andric 6010b57cec5SDimitry Andric CommandOptions m_options; 6020b57cec5SDimitry Andric ModuleList m_module_list; 6030b57cec5SDimitry Andric }; 6040b57cec5SDimitry Andric 6050b57cec5SDimitry Andric #pragma mark CommandObjectSourceList 6060b57cec5SDimitry Andric // CommandObjectSourceList 6079dba64beSDimitry Andric #define LLDB_OPTIONS_source_list 6089dba64beSDimitry Andric #include "CommandOptions.inc" 6090b57cec5SDimitry Andric 6100b57cec5SDimitry Andric class CommandObjectSourceList : public CommandObjectParsed { 6110b57cec5SDimitry Andric class CommandOptions : public Options { 6120b57cec5SDimitry Andric public: 61381ad6265SDimitry Andric CommandOptions() = default; 6140b57cec5SDimitry Andric 6150b57cec5SDimitry Andric ~CommandOptions() override = default; 6160b57cec5SDimitry Andric 6170b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 6180b57cec5SDimitry Andric ExecutionContext *execution_context) override { 6190b57cec5SDimitry Andric Status error; 6200b57cec5SDimitry Andric const int short_option = GetDefinitions()[option_idx].short_option; 6210b57cec5SDimitry Andric switch (short_option) { 6220b57cec5SDimitry Andric case 'l': 6230b57cec5SDimitry Andric if (option_arg.getAsInteger(0, start_line)) 6240b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line number: '%s'", 6250b57cec5SDimitry Andric option_arg.str().c_str()); 6260b57cec5SDimitry Andric break; 6270b57cec5SDimitry Andric 6280b57cec5SDimitry Andric case 'c': 6290b57cec5SDimitry Andric if (option_arg.getAsInteger(0, num_lines)) 6300b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line count: '%s'", 6310b57cec5SDimitry Andric option_arg.str().c_str()); 6320b57cec5SDimitry Andric break; 6330b57cec5SDimitry Andric 6340b57cec5SDimitry Andric case 'f': 6355ffd83dbSDimitry Andric file_name = std::string(option_arg); 6360b57cec5SDimitry Andric break; 6370b57cec5SDimitry Andric 6380b57cec5SDimitry Andric case 'n': 6395ffd83dbSDimitry Andric symbol_name = std::string(option_arg); 6400b57cec5SDimitry Andric break; 6410b57cec5SDimitry Andric 6420b57cec5SDimitry Andric case 'a': { 6430b57cec5SDimitry Andric address = OptionArgParser::ToAddress(execution_context, option_arg, 6440b57cec5SDimitry Andric LLDB_INVALID_ADDRESS, &error); 6450b57cec5SDimitry Andric } break; 6460b57cec5SDimitry Andric case 's': 6470b57cec5SDimitry Andric modules.push_back(std::string(option_arg)); 6480b57cec5SDimitry Andric break; 6490b57cec5SDimitry Andric 6500b57cec5SDimitry Andric case 'b': 6510b57cec5SDimitry Andric show_bp_locs = true; 6520b57cec5SDimitry Andric break; 6530b57cec5SDimitry Andric case 'r': 6540b57cec5SDimitry Andric reverse = true; 6550b57cec5SDimitry Andric break; 656e8d8bef9SDimitry Andric case 'y': 657e8d8bef9SDimitry Andric { 658e8d8bef9SDimitry Andric OptionValueFileColonLine value; 659e8d8bef9SDimitry Andric Status fcl_err = value.SetValueFromString(option_arg); 660e8d8bef9SDimitry Andric if (!fcl_err.Success()) { 661e8d8bef9SDimitry Andric error.SetErrorStringWithFormat( 662e8d8bef9SDimitry Andric "Invalid value for file:line specifier: %s", 663e8d8bef9SDimitry Andric fcl_err.AsCString()); 664e8d8bef9SDimitry Andric } else { 665e8d8bef9SDimitry Andric file_name = value.GetFileSpec().GetPath(); 666e8d8bef9SDimitry Andric start_line = value.GetLineNumber(); 667e8d8bef9SDimitry Andric // I don't see anything useful to do with a column number, but I don't 668e8d8bef9SDimitry Andric // want to complain since someone may well have cut and pasted a 669e8d8bef9SDimitry Andric // listing from somewhere that included a column. 670e8d8bef9SDimitry Andric } 671e8d8bef9SDimitry Andric } break; 6720b57cec5SDimitry Andric default: 6739dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 6740b57cec5SDimitry Andric } 6750b57cec5SDimitry Andric 6760b57cec5SDimitry Andric return error; 6770b57cec5SDimitry Andric } 6780b57cec5SDimitry Andric 6790b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 6800b57cec5SDimitry Andric file_spec.Clear(); 6810b57cec5SDimitry Andric file_name.clear(); 6820b57cec5SDimitry Andric symbol_name.clear(); 6830b57cec5SDimitry Andric address = LLDB_INVALID_ADDRESS; 6840b57cec5SDimitry Andric start_line = 0; 6850b57cec5SDimitry Andric num_lines = 0; 6860b57cec5SDimitry Andric show_bp_locs = false; 6870b57cec5SDimitry Andric reverse = false; 6880b57cec5SDimitry Andric modules.clear(); 6890b57cec5SDimitry Andric } 6900b57cec5SDimitry Andric 6910b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 692bdd1243dSDimitry Andric return llvm::ArrayRef(g_source_list_options); 6930b57cec5SDimitry Andric } 6940b57cec5SDimitry Andric 6950b57cec5SDimitry Andric // Instance variables to hold the values for command options. 6960b57cec5SDimitry Andric FileSpec file_spec; 6970b57cec5SDimitry Andric std::string file_name; 6980b57cec5SDimitry Andric std::string symbol_name; 6990b57cec5SDimitry Andric lldb::addr_t address; 7000b57cec5SDimitry Andric uint32_t start_line; 7010b57cec5SDimitry Andric uint32_t num_lines; 702480093f4SDimitry Andric std::vector<std::string> modules; 7030b57cec5SDimitry Andric bool show_bp_locs; 7040b57cec5SDimitry Andric bool reverse; 7050b57cec5SDimitry Andric }; 7060b57cec5SDimitry Andric 7070b57cec5SDimitry Andric public: 7080b57cec5SDimitry Andric CommandObjectSourceList(CommandInterpreter &interpreter) 7090b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "source list", 7100b57cec5SDimitry Andric "Display source code for the current target " 7110b57cec5SDimitry Andric "process as specified by options.", 71204eeddc0SDimitry Andric nullptr, eCommandRequiresTarget) {} 7130b57cec5SDimitry Andric 7140b57cec5SDimitry Andric ~CommandObjectSourceList() override = default; 7150b57cec5SDimitry Andric 7160b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 7170b57cec5SDimitry Andric 718bdd1243dSDimitry Andric std::optional<std::string> GetRepeatCommand(Args ¤t_command_args, 7190b57cec5SDimitry Andric uint32_t index) override { 7200b57cec5SDimitry Andric // This is kind of gross, but the command hasn't been parsed yet so we 7210b57cec5SDimitry Andric // can't look at the option values for this invocation... I have to scan 7220b57cec5SDimitry Andric // the arguments directly. 7230b57cec5SDimitry Andric auto iter = 7240b57cec5SDimitry Andric llvm::find_if(current_command_args, [](const Args::ArgEntry &e) { 7259dba64beSDimitry Andric return e.ref() == "-r" || e.ref() == "--reverse"; 7260b57cec5SDimitry Andric }); 7270b57cec5SDimitry Andric if (iter == current_command_args.end()) 72881ad6265SDimitry Andric return m_cmd_name; 7290b57cec5SDimitry Andric 7300b57cec5SDimitry Andric if (m_reverse_name.empty()) { 7310b57cec5SDimitry Andric m_reverse_name = m_cmd_name; 7320b57cec5SDimitry Andric m_reverse_name.append(" -r"); 7330b57cec5SDimitry Andric } 73481ad6265SDimitry Andric return m_reverse_name; 7350b57cec5SDimitry Andric } 7360b57cec5SDimitry Andric 7370b57cec5SDimitry Andric protected: 7380b57cec5SDimitry Andric struct SourceInfo { 7390b57cec5SDimitry Andric ConstString function; 7400b57cec5SDimitry Andric LineEntry line_entry; 7410b57cec5SDimitry Andric 7420b57cec5SDimitry Andric SourceInfo(ConstString name, const LineEntry &line_entry) 7430b57cec5SDimitry Andric : function(name), line_entry(line_entry) {} 7440b57cec5SDimitry Andric 74581ad6265SDimitry Andric SourceInfo() = default; 7460b57cec5SDimitry Andric 7470b57cec5SDimitry Andric bool IsValid() const { return (bool)function && line_entry.IsValid(); } 7480b57cec5SDimitry Andric 7490b57cec5SDimitry Andric bool operator==(const SourceInfo &rhs) const { 7500b57cec5SDimitry Andric return function == rhs.function && 7510b57cec5SDimitry Andric line_entry.original_file == rhs.line_entry.original_file && 7520b57cec5SDimitry Andric line_entry.line == rhs.line_entry.line; 7530b57cec5SDimitry Andric } 7540b57cec5SDimitry Andric 7550b57cec5SDimitry Andric bool operator!=(const SourceInfo &rhs) const { 7560b57cec5SDimitry Andric return function != rhs.function || 7570b57cec5SDimitry Andric line_entry.original_file != rhs.line_entry.original_file || 7580b57cec5SDimitry Andric line_entry.line != rhs.line_entry.line; 7590b57cec5SDimitry Andric } 7600b57cec5SDimitry Andric 7610b57cec5SDimitry Andric bool operator<(const SourceInfo &rhs) const { 7620b57cec5SDimitry Andric if (function.GetCString() < rhs.function.GetCString()) 7630b57cec5SDimitry Andric return true; 7640b57cec5SDimitry Andric if (line_entry.file.GetDirectory().GetCString() < 7650b57cec5SDimitry Andric rhs.line_entry.file.GetDirectory().GetCString()) 7660b57cec5SDimitry Andric return true; 7670b57cec5SDimitry Andric if (line_entry.file.GetFilename().GetCString() < 7680b57cec5SDimitry Andric rhs.line_entry.file.GetFilename().GetCString()) 7690b57cec5SDimitry Andric return true; 7700b57cec5SDimitry Andric if (line_entry.line < rhs.line_entry.line) 7710b57cec5SDimitry Andric return true; 7720b57cec5SDimitry Andric return false; 7730b57cec5SDimitry Andric } 7740b57cec5SDimitry Andric }; 7750b57cec5SDimitry Andric 7760b57cec5SDimitry Andric size_t DisplayFunctionSource(const SymbolContext &sc, SourceInfo &source_info, 7770b57cec5SDimitry Andric CommandReturnObject &result) { 7780b57cec5SDimitry Andric if (!source_info.IsValid()) { 7790b57cec5SDimitry Andric source_info.function = sc.GetFunctionName(); 7800b57cec5SDimitry Andric source_info.line_entry = sc.GetFunctionStartLineEntry(); 7810b57cec5SDimitry Andric } 7820b57cec5SDimitry Andric 7830b57cec5SDimitry Andric if (sc.function) { 7840b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 7850b57cec5SDimitry Andric 7860b57cec5SDimitry Andric FileSpec start_file; 7870b57cec5SDimitry Andric uint32_t start_line; 7880b57cec5SDimitry Andric uint32_t end_line; 7890b57cec5SDimitry Andric FileSpec end_file; 7900b57cec5SDimitry Andric 7910b57cec5SDimitry Andric if (sc.block == nullptr) { 7920b57cec5SDimitry Andric // Not an inlined function 7930b57cec5SDimitry Andric sc.function->GetStartLineSourceInfo(start_file, start_line); 7940b57cec5SDimitry Andric if (start_line == 0) { 7950b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find line information for " 7960b57cec5SDimitry Andric "start of function: \"%s\".\n", 7970b57cec5SDimitry Andric source_info.function.GetCString()); 7980b57cec5SDimitry Andric return 0; 7990b57cec5SDimitry Andric } 8000b57cec5SDimitry Andric sc.function->GetEndLineSourceInfo(end_file, end_line); 8010b57cec5SDimitry Andric } else { 8020b57cec5SDimitry Andric // We have an inlined function 8030b57cec5SDimitry Andric start_file = source_info.line_entry.file; 8040b57cec5SDimitry Andric start_line = source_info.line_entry.line; 8050b57cec5SDimitry Andric end_line = start_line + m_options.num_lines; 8060b57cec5SDimitry Andric } 8070b57cec5SDimitry Andric 8080b57cec5SDimitry Andric // This is a little hacky, but the first line table entry for a function 8090b57cec5SDimitry Andric // points to the "{" that starts the function block. It would be nice to 8100b57cec5SDimitry Andric // actually get the function declaration in there too. So back up a bit, 8110b57cec5SDimitry Andric // but not further than what you're going to display. 8120b57cec5SDimitry Andric uint32_t extra_lines; 8130b57cec5SDimitry Andric if (m_options.num_lines >= 10) 8140b57cec5SDimitry Andric extra_lines = 5; 8150b57cec5SDimitry Andric else 8160b57cec5SDimitry Andric extra_lines = m_options.num_lines / 2; 8170b57cec5SDimitry Andric uint32_t line_no; 8180b57cec5SDimitry Andric if (start_line <= extra_lines) 8190b57cec5SDimitry Andric line_no = 1; 8200b57cec5SDimitry Andric else 8210b57cec5SDimitry Andric line_no = start_line - extra_lines; 8220b57cec5SDimitry Andric 8230b57cec5SDimitry Andric // For fun, if the function is shorter than the number of lines we're 8240b57cec5SDimitry Andric // supposed to display, only display the function... 8250b57cec5SDimitry Andric if (end_line != 0) { 8260b57cec5SDimitry Andric if (m_options.num_lines > end_line - line_no) 8270b57cec5SDimitry Andric m_options.num_lines = end_line - line_no + extra_lines; 8280b57cec5SDimitry Andric } 8290b57cec5SDimitry Andric 8300b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 8310b57cec5SDimitry Andric 8320b57cec5SDimitry Andric if (m_options.show_bp_locs) { 8330b57cec5SDimitry Andric const bool show_inlines = true; 8340b57cec5SDimitry Andric m_breakpoint_locations.Reset(start_file, 0, show_inlines); 8350b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 8360b57cec5SDimitry Andric m_exe_ctx.GetTargetSP()); 8370b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 8380b57cec5SDimitry Andric } 8390b57cec5SDimitry Andric 8400b57cec5SDimitry Andric result.AppendMessageWithFormat("File: %s\n", 8410b57cec5SDimitry Andric start_file.GetPath().c_str()); 8420b57cec5SDimitry Andric // We don't care about the column here. 8430b57cec5SDimitry Andric const uint32_t column = 0; 8440b57cec5SDimitry Andric return target->GetSourceManager().DisplaySourceLinesWithLineNumbers( 8450b57cec5SDimitry Andric start_file, line_no, column, 0, m_options.num_lines, "", 8460b57cec5SDimitry Andric &result.GetOutputStream(), GetBreakpointLocations()); 8470b57cec5SDimitry Andric } else { 8480b57cec5SDimitry Andric result.AppendErrorWithFormat( 8490b57cec5SDimitry Andric "Could not find function info for: \"%s\".\n", 8500b57cec5SDimitry Andric m_options.symbol_name.c_str()); 8510b57cec5SDimitry Andric } 8520b57cec5SDimitry Andric return 0; 8530b57cec5SDimitry Andric } 8540b57cec5SDimitry Andric 8550b57cec5SDimitry Andric // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols 8560b57cec5SDimitry Andric // functions "take a possibly empty vector of strings which are names of 8570b57cec5SDimitry Andric // modules, and run the two search functions on the subset of the full module 8580b57cec5SDimitry Andric // list that matches the strings in the input vector". If we wanted to put 8590b57cec5SDimitry Andric // these somewhere, there should probably be a module-filter-list that can be 8600b57cec5SDimitry Andric // passed to the various ModuleList::Find* calls, which would either be a 8610b57cec5SDimitry Andric // vector of string names or a ModuleSpecList. 8629dba64beSDimitry Andric void FindMatchingFunctions(Target *target, ConstString name, 8630b57cec5SDimitry Andric SymbolContextList &sc_list) { 8640b57cec5SDimitry Andric // Displaying the source for a symbol: 8650b57cec5SDimitry Andric if (m_options.num_lines == 0) 8660b57cec5SDimitry Andric m_options.num_lines = 10; 8670b57cec5SDimitry Andric 868349cc55cSDimitry Andric ModuleFunctionSearchOptions function_options; 869349cc55cSDimitry Andric function_options.include_symbols = true; 870349cc55cSDimitry Andric function_options.include_inlines = false; 871349cc55cSDimitry Andric 8720b57cec5SDimitry Andric const size_t num_modules = m_options.modules.size(); 8730b57cec5SDimitry Andric if (num_modules > 0) { 8740b57cec5SDimitry Andric ModuleList matching_modules; 8750b57cec5SDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 8760b57cec5SDimitry Andric FileSpec module_file_spec(m_options.modules[i]); 8770b57cec5SDimitry Andric if (module_file_spec) { 8780b57cec5SDimitry Andric ModuleSpec module_spec(module_file_spec); 8790b57cec5SDimitry Andric matching_modules.Clear(); 8800b57cec5SDimitry Andric target->GetImages().FindModules(module_spec, matching_modules); 881349cc55cSDimitry Andric 882480093f4SDimitry Andric matching_modules.FindFunctions(name, eFunctionNameTypeAuto, 883349cc55cSDimitry Andric function_options, sc_list); 8840b57cec5SDimitry Andric } 8850b57cec5SDimitry Andric } 8860b57cec5SDimitry Andric } else { 8879dba64beSDimitry Andric target->GetImages().FindFunctions(name, eFunctionNameTypeAuto, 888349cc55cSDimitry Andric function_options, sc_list); 8890b57cec5SDimitry Andric } 8900b57cec5SDimitry Andric } 8910b57cec5SDimitry Andric 8929dba64beSDimitry Andric void FindMatchingFunctionSymbols(Target *target, ConstString name, 8930b57cec5SDimitry Andric SymbolContextList &sc_list) { 8940b57cec5SDimitry Andric const size_t num_modules = m_options.modules.size(); 8950b57cec5SDimitry Andric if (num_modules > 0) { 8960b57cec5SDimitry Andric ModuleList matching_modules; 8970b57cec5SDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 8980b57cec5SDimitry Andric FileSpec module_file_spec(m_options.modules[i]); 8990b57cec5SDimitry Andric if (module_file_spec) { 9000b57cec5SDimitry Andric ModuleSpec module_spec(module_file_spec); 9010b57cec5SDimitry Andric matching_modules.Clear(); 9020b57cec5SDimitry Andric target->GetImages().FindModules(module_spec, matching_modules); 9039dba64beSDimitry Andric matching_modules.FindFunctionSymbols(name, eFunctionNameTypeAuto, 9049dba64beSDimitry Andric sc_list); 9050b57cec5SDimitry Andric } 9060b57cec5SDimitry Andric } 9070b57cec5SDimitry Andric } else { 9089dba64beSDimitry Andric target->GetImages().FindFunctionSymbols(name, eFunctionNameTypeAuto, 9099dba64beSDimitry Andric sc_list); 9100b57cec5SDimitry Andric } 9110b57cec5SDimitry Andric } 9120b57cec5SDimitry Andric 9130b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 9140b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 9150b57cec5SDimitry Andric 9160b57cec5SDimitry Andric if (!m_options.symbol_name.empty()) { 9170b57cec5SDimitry Andric SymbolContextList sc_list; 9180b57cec5SDimitry Andric ConstString name(m_options.symbol_name.c_str()); 9190b57cec5SDimitry Andric 9200b57cec5SDimitry Andric // Displaying the source for a symbol. Search for function named name. 9219dba64beSDimitry Andric FindMatchingFunctions(target, name, sc_list); 922*fe013be4SDimitry Andric if (sc_list.GetSize() == 0) { 9230b57cec5SDimitry Andric // If we didn't find any functions with that name, try searching for 9240b57cec5SDimitry Andric // symbols that line up exactly with function addresses. 9250b57cec5SDimitry Andric SymbolContextList sc_list_symbols; 9260b57cec5SDimitry Andric FindMatchingFunctionSymbols(target, name, sc_list_symbols); 927*fe013be4SDimitry Andric for (const SymbolContext &sc : sc_list_symbols) { 9280b57cec5SDimitry Andric if (sc.symbol && sc.symbol->ValueIsAddress()) { 9290b57cec5SDimitry Andric const Address &base_address = sc.symbol->GetAddressRef(); 9300b57cec5SDimitry Andric Function *function = base_address.CalculateSymbolContextFunction(); 9310b57cec5SDimitry Andric if (function) { 9320b57cec5SDimitry Andric sc_list.Append(SymbolContext(function)); 9330b57cec5SDimitry Andric break; 9340b57cec5SDimitry Andric } 9350b57cec5SDimitry Andric } 9360b57cec5SDimitry Andric } 9370b57cec5SDimitry Andric } 9380b57cec5SDimitry Andric 939*fe013be4SDimitry Andric if (sc_list.GetSize() == 0) { 9400b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find function named: \"%s\".\n", 9410b57cec5SDimitry Andric m_options.symbol_name.c_str()); 9420b57cec5SDimitry Andric return false; 9430b57cec5SDimitry Andric } 9440b57cec5SDimitry Andric 9450b57cec5SDimitry Andric std::set<SourceInfo> source_match_set; 9460b57cec5SDimitry Andric bool displayed_something = false; 947*fe013be4SDimitry Andric for (const SymbolContext &sc : sc_list) { 9480b57cec5SDimitry Andric SourceInfo source_info(sc.GetFunctionName(), 9490b57cec5SDimitry Andric sc.GetFunctionStartLineEntry()); 950*fe013be4SDimitry Andric if (source_info.IsValid() && 951*fe013be4SDimitry Andric source_match_set.find(source_info) == source_match_set.end()) { 9520b57cec5SDimitry Andric source_match_set.insert(source_info); 9530b57cec5SDimitry Andric if (DisplayFunctionSource(sc, source_info, result)) 9540b57cec5SDimitry Andric displayed_something = true; 9550b57cec5SDimitry Andric } 9560b57cec5SDimitry Andric } 9570b57cec5SDimitry Andric if (displayed_something) 9580b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 9590b57cec5SDimitry Andric else 9600b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 9610b57cec5SDimitry Andric return result.Succeeded(); 9620b57cec5SDimitry Andric } else if (m_options.address != LLDB_INVALID_ADDRESS) { 9630b57cec5SDimitry Andric Address so_addr; 9640b57cec5SDimitry Andric StreamString error_strm; 9650b57cec5SDimitry Andric SymbolContextList sc_list; 9660b57cec5SDimitry Andric 9670b57cec5SDimitry Andric if (target->GetSectionLoadList().IsEmpty()) { 9680b57cec5SDimitry Andric // The target isn't loaded yet, we need to lookup the file address in 9690b57cec5SDimitry Andric // all modules 9700b57cec5SDimitry Andric const ModuleList &module_list = target->GetImages(); 9710b57cec5SDimitry Andric const size_t num_modules = module_list.GetSize(); 9720b57cec5SDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 9730b57cec5SDimitry Andric ModuleSP module_sp(module_list.GetModuleAtIndex(i)); 9740b57cec5SDimitry Andric if (module_sp && 9750b57cec5SDimitry Andric module_sp->ResolveFileAddress(m_options.address, so_addr)) { 9760b57cec5SDimitry Andric SymbolContext sc; 9770b57cec5SDimitry Andric sc.Clear(true); 9780b57cec5SDimitry Andric if (module_sp->ResolveSymbolContextForAddress( 9790b57cec5SDimitry Andric so_addr, eSymbolContextEverything, sc) & 9800b57cec5SDimitry Andric eSymbolContextLineEntry) 9810b57cec5SDimitry Andric sc_list.Append(sc); 9820b57cec5SDimitry Andric } 9830b57cec5SDimitry Andric } 9840b57cec5SDimitry Andric 9850b57cec5SDimitry Andric if (sc_list.GetSize() == 0) { 9860b57cec5SDimitry Andric result.AppendErrorWithFormat( 9870b57cec5SDimitry Andric "no modules have source information for file address 0x%" PRIx64 9880b57cec5SDimitry Andric ".\n", 9890b57cec5SDimitry Andric m_options.address); 9900b57cec5SDimitry Andric return false; 9910b57cec5SDimitry Andric } 9920b57cec5SDimitry Andric } else { 9930b57cec5SDimitry Andric // The target has some things loaded, resolve this address to a compile 9940b57cec5SDimitry Andric // unit + file + line and display 9950b57cec5SDimitry Andric if (target->GetSectionLoadList().ResolveLoadAddress(m_options.address, 9960b57cec5SDimitry Andric so_addr)) { 9970b57cec5SDimitry Andric ModuleSP module_sp(so_addr.GetModule()); 9980b57cec5SDimitry Andric if (module_sp) { 9990b57cec5SDimitry Andric SymbolContext sc; 10000b57cec5SDimitry Andric sc.Clear(true); 10010b57cec5SDimitry Andric if (module_sp->ResolveSymbolContextForAddress( 10020b57cec5SDimitry Andric so_addr, eSymbolContextEverything, sc) & 10030b57cec5SDimitry Andric eSymbolContextLineEntry) { 10040b57cec5SDimitry Andric sc_list.Append(sc); 10050b57cec5SDimitry Andric } else { 10060b57cec5SDimitry Andric so_addr.Dump(&error_strm, nullptr, 10070b57cec5SDimitry Andric Address::DumpStyleModuleWithFileAddress); 10080b57cec5SDimitry Andric result.AppendErrorWithFormat("address resolves to %s, but there " 10090b57cec5SDimitry Andric "is no line table information " 10100b57cec5SDimitry Andric "available for this address.\n", 10110b57cec5SDimitry Andric error_strm.GetData()); 10120b57cec5SDimitry Andric return false; 10130b57cec5SDimitry Andric } 10140b57cec5SDimitry Andric } 10150b57cec5SDimitry Andric } 10160b57cec5SDimitry Andric 10170b57cec5SDimitry Andric if (sc_list.GetSize() == 0) { 10180b57cec5SDimitry Andric result.AppendErrorWithFormat( 10190b57cec5SDimitry Andric "no modules contain load address 0x%" PRIx64 ".\n", 10200b57cec5SDimitry Andric m_options.address); 10210b57cec5SDimitry Andric return false; 10220b57cec5SDimitry Andric } 10230b57cec5SDimitry Andric } 1024*fe013be4SDimitry Andric for (const SymbolContext &sc : sc_list) { 10250b57cec5SDimitry Andric if (sc.comp_unit) { 10260b57cec5SDimitry Andric if (m_options.show_bp_locs) { 10270b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 10280b57cec5SDimitry Andric const bool show_inlines = true; 1029480093f4SDimitry Andric m_breakpoint_locations.Reset(sc.comp_unit->GetPrimaryFile(), 0, 1030480093f4SDimitry Andric show_inlines); 10310b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 10320b57cec5SDimitry Andric target->shared_from_this()); 10330b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 10340b57cec5SDimitry Andric } 10350b57cec5SDimitry Andric 10360b57cec5SDimitry Andric bool show_fullpaths = true; 10370b57cec5SDimitry Andric bool show_module = true; 10380b57cec5SDimitry Andric bool show_inlined_frames = true; 10390b57cec5SDimitry Andric const bool show_function_arguments = true; 10400b57cec5SDimitry Andric const bool show_function_name = true; 10410b57cec5SDimitry Andric sc.DumpStopContext(&result.GetOutputStream(), 10420b57cec5SDimitry Andric m_exe_ctx.GetBestExecutionContextScope(), 10430b57cec5SDimitry Andric sc.line_entry.range.GetBaseAddress(), 10440b57cec5SDimitry Andric show_fullpaths, show_module, show_inlined_frames, 10450b57cec5SDimitry Andric show_function_arguments, show_function_name); 10460b57cec5SDimitry Andric result.GetOutputStream().EOL(); 10470b57cec5SDimitry Andric 10480b57cec5SDimitry Andric if (m_options.num_lines == 0) 10490b57cec5SDimitry Andric m_options.num_lines = 10; 10500b57cec5SDimitry Andric 10510b57cec5SDimitry Andric size_t lines_to_back_up = 10520b57cec5SDimitry Andric m_options.num_lines >= 10 ? 5 : m_options.num_lines / 2; 10530b57cec5SDimitry Andric 10540b57cec5SDimitry Andric const uint32_t column = 10550b57cec5SDimitry Andric (GetDebugger().GetStopShowColumn() != eStopShowColumnNone) 10560b57cec5SDimitry Andric ? sc.line_entry.column 10570b57cec5SDimitry Andric : 0; 10580b57cec5SDimitry Andric target->GetSourceManager().DisplaySourceLinesWithLineNumbers( 1059480093f4SDimitry Andric sc.comp_unit->GetPrimaryFile(), sc.line_entry.line, column, 1060480093f4SDimitry Andric lines_to_back_up, m_options.num_lines - lines_to_back_up, "->", 10610b57cec5SDimitry Andric &result.GetOutputStream(), GetBreakpointLocations()); 10620b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 10630b57cec5SDimitry Andric } 10640b57cec5SDimitry Andric } 10650b57cec5SDimitry Andric } else if (m_options.file_name.empty()) { 10660b57cec5SDimitry Andric // Last valid source manager context, or the current frame if no valid 10670b57cec5SDimitry Andric // last context in source manager. One little trick here, if you type the 10680b57cec5SDimitry Andric // exact same list command twice in a row, it is more likely because you 10690b57cec5SDimitry Andric // typed it once, then typed it again 10700b57cec5SDimitry Andric if (m_options.start_line == 0) { 10710b57cec5SDimitry Andric if (target->GetSourceManager().DisplayMoreWithLineNumbers( 10720b57cec5SDimitry Andric &result.GetOutputStream(), m_options.num_lines, 10730b57cec5SDimitry Andric m_options.reverse, GetBreakpointLocations())) { 10740b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 10750b57cec5SDimitry Andric } 10760b57cec5SDimitry Andric } else { 10770b57cec5SDimitry Andric if (m_options.num_lines == 0) 10780b57cec5SDimitry Andric m_options.num_lines = 10; 10790b57cec5SDimitry Andric 10800b57cec5SDimitry Andric if (m_options.show_bp_locs) { 10810b57cec5SDimitry Andric SourceManager::FileSP last_file_sp( 10820b57cec5SDimitry Andric target->GetSourceManager().GetLastFile()); 10830b57cec5SDimitry Andric if (last_file_sp) { 10840b57cec5SDimitry Andric const bool show_inlines = true; 10850b57cec5SDimitry Andric m_breakpoint_locations.Reset(last_file_sp->GetFileSpec(), 0, 10860b57cec5SDimitry Andric show_inlines); 10870b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 10880b57cec5SDimitry Andric target->shared_from_this()); 10890b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 10900b57cec5SDimitry Andric } 10910b57cec5SDimitry Andric } else 10920b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 10930b57cec5SDimitry Andric 10940b57cec5SDimitry Andric const uint32_t column = 0; 10950b57cec5SDimitry Andric if (target->GetSourceManager() 10960b57cec5SDimitry Andric .DisplaySourceLinesWithLineNumbersUsingLastFile( 10970b57cec5SDimitry Andric m_options.start_line, // Line to display 10980b57cec5SDimitry Andric m_options.num_lines, // Lines after line to 10990b57cec5SDimitry Andric UINT32_MAX, // Don't mark "line" 11000b57cec5SDimitry Andric column, 11010b57cec5SDimitry Andric "", // Don't mark "line" 11020b57cec5SDimitry Andric &result.GetOutputStream(), GetBreakpointLocations())) { 11030b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 11040b57cec5SDimitry Andric } 11050b57cec5SDimitry Andric } 11060b57cec5SDimitry Andric } else { 11070b57cec5SDimitry Andric const char *filename = m_options.file_name.c_str(); 11080b57cec5SDimitry Andric 11090b57cec5SDimitry Andric bool check_inlines = false; 11100b57cec5SDimitry Andric SymbolContextList sc_list; 11110b57cec5SDimitry Andric size_t num_matches = 0; 11120b57cec5SDimitry Andric 11130b57cec5SDimitry Andric if (!m_options.modules.empty()) { 11140b57cec5SDimitry Andric ModuleList matching_modules; 11150b57cec5SDimitry Andric for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) { 11160b57cec5SDimitry Andric FileSpec module_file_spec(m_options.modules[i]); 11170b57cec5SDimitry Andric if (module_file_spec) { 11180b57cec5SDimitry Andric ModuleSpec module_spec(module_file_spec); 11190b57cec5SDimitry Andric matching_modules.Clear(); 11200b57cec5SDimitry Andric target->GetImages().FindModules(module_spec, matching_modules); 11210b57cec5SDimitry Andric num_matches += matching_modules.ResolveSymbolContextForFilePath( 11220b57cec5SDimitry Andric filename, 0, check_inlines, 11230b57cec5SDimitry Andric SymbolContextItem(eSymbolContextModule | 11240b57cec5SDimitry Andric eSymbolContextCompUnit), 11250b57cec5SDimitry Andric sc_list); 11260b57cec5SDimitry Andric } 11270b57cec5SDimitry Andric } 11280b57cec5SDimitry Andric } else { 11290b57cec5SDimitry Andric num_matches = target->GetImages().ResolveSymbolContextForFilePath( 11300b57cec5SDimitry Andric filename, 0, check_inlines, 11310b57cec5SDimitry Andric eSymbolContextModule | eSymbolContextCompUnit, sc_list); 11320b57cec5SDimitry Andric } 11330b57cec5SDimitry Andric 11340b57cec5SDimitry Andric if (num_matches == 0) { 11350b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find source file \"%s\".\n", 11360b57cec5SDimitry Andric m_options.file_name.c_str()); 11370b57cec5SDimitry Andric return false; 11380b57cec5SDimitry Andric } 11390b57cec5SDimitry Andric 11400b57cec5SDimitry Andric if (num_matches > 1) { 11410b57cec5SDimitry Andric bool got_multiple = false; 1142480093f4SDimitry Andric CompileUnit *test_cu = nullptr; 11430b57cec5SDimitry Andric 1144*fe013be4SDimitry Andric for (const SymbolContext &sc : sc_list) { 11450b57cec5SDimitry Andric if (sc.comp_unit) { 1146480093f4SDimitry Andric if (test_cu) { 1147480093f4SDimitry Andric if (test_cu != sc.comp_unit) 11480b57cec5SDimitry Andric got_multiple = true; 11490b57cec5SDimitry Andric break; 11500b57cec5SDimitry Andric } else 1151480093f4SDimitry Andric test_cu = sc.comp_unit; 11520b57cec5SDimitry Andric } 11530b57cec5SDimitry Andric } 11540b57cec5SDimitry Andric if (got_multiple) { 11550b57cec5SDimitry Andric result.AppendErrorWithFormat( 11560b57cec5SDimitry Andric "Multiple source files found matching: \"%s.\"\n", 11570b57cec5SDimitry Andric m_options.file_name.c_str()); 11580b57cec5SDimitry Andric return false; 11590b57cec5SDimitry Andric } 11600b57cec5SDimitry Andric } 11610b57cec5SDimitry Andric 11620b57cec5SDimitry Andric SymbolContext sc; 11630b57cec5SDimitry Andric if (sc_list.GetContextAtIndex(0, sc)) { 11640b57cec5SDimitry Andric if (sc.comp_unit) { 11650b57cec5SDimitry Andric if (m_options.show_bp_locs) { 11660b57cec5SDimitry Andric const bool show_inlines = true; 1167480093f4SDimitry Andric m_breakpoint_locations.Reset(sc.comp_unit->GetPrimaryFile(), 0, 1168480093f4SDimitry Andric show_inlines); 11690b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 11700b57cec5SDimitry Andric target->shared_from_this()); 11710b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 11720b57cec5SDimitry Andric } else 11730b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 11740b57cec5SDimitry Andric 11750b57cec5SDimitry Andric if (m_options.num_lines == 0) 11760b57cec5SDimitry Andric m_options.num_lines = 10; 11770b57cec5SDimitry Andric const uint32_t column = 0; 11780b57cec5SDimitry Andric target->GetSourceManager().DisplaySourceLinesWithLineNumbers( 1179480093f4SDimitry Andric sc.comp_unit->GetPrimaryFile(), m_options.start_line, column, 0, 1180480093f4SDimitry Andric m_options.num_lines, "", &result.GetOutputStream(), 1181480093f4SDimitry Andric GetBreakpointLocations()); 11820b57cec5SDimitry Andric 11830b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 11840b57cec5SDimitry Andric } else { 11850b57cec5SDimitry Andric result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n", 11860b57cec5SDimitry Andric m_options.file_name.c_str()); 11870b57cec5SDimitry Andric return false; 11880b57cec5SDimitry Andric } 11890b57cec5SDimitry Andric } 11900b57cec5SDimitry Andric } 11910b57cec5SDimitry Andric return result.Succeeded(); 11920b57cec5SDimitry Andric } 11930b57cec5SDimitry Andric 11940b57cec5SDimitry Andric const SymbolContextList *GetBreakpointLocations() { 11950b57cec5SDimitry Andric if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0) 11960b57cec5SDimitry Andric return &m_breakpoint_locations.GetFileLineMatches(); 11970b57cec5SDimitry Andric return nullptr; 11980b57cec5SDimitry Andric } 11990b57cec5SDimitry Andric 12000b57cec5SDimitry Andric CommandOptions m_options; 12010b57cec5SDimitry Andric FileLineResolver m_breakpoint_locations; 12020b57cec5SDimitry Andric std::string m_reverse_name; 12030b57cec5SDimitry Andric }; 12040b57cec5SDimitry Andric 1205*fe013be4SDimitry Andric class CommandObjectSourceCacheDump : public CommandObjectParsed { 1206*fe013be4SDimitry Andric public: 1207*fe013be4SDimitry Andric CommandObjectSourceCacheDump(CommandInterpreter &interpreter) 1208*fe013be4SDimitry Andric : CommandObjectParsed(interpreter, "source cache dump", 1209*fe013be4SDimitry Andric "Dump the state of the source code cache. Intended " 1210*fe013be4SDimitry Andric "to be used for debugging LLDB itself.", 1211*fe013be4SDimitry Andric nullptr) {} 1212*fe013be4SDimitry Andric 1213*fe013be4SDimitry Andric ~CommandObjectSourceCacheDump() override = default; 1214*fe013be4SDimitry Andric 1215*fe013be4SDimitry Andric protected: 1216*fe013be4SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 1217*fe013be4SDimitry Andric // Dump the debugger source cache. 1218*fe013be4SDimitry Andric result.GetOutputStream() << "Debugger Source File Cache\n"; 1219*fe013be4SDimitry Andric SourceManager::SourceFileCache &cache = GetDebugger().GetSourceFileCache(); 1220*fe013be4SDimitry Andric cache.Dump(result.GetOutputStream()); 1221*fe013be4SDimitry Andric 1222*fe013be4SDimitry Andric // Dump the process source cache. 1223*fe013be4SDimitry Andric if (ProcessSP process_sp = m_exe_ctx.GetProcessSP()) { 1224*fe013be4SDimitry Andric result.GetOutputStream() << "\nProcess Source File Cache\n"; 1225*fe013be4SDimitry Andric SourceManager::SourceFileCache &cache = process_sp->GetSourceFileCache(); 1226*fe013be4SDimitry Andric cache.Dump(result.GetOutputStream()); 1227*fe013be4SDimitry Andric } 1228*fe013be4SDimitry Andric 1229*fe013be4SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 1230*fe013be4SDimitry Andric return result.Succeeded(); 1231*fe013be4SDimitry Andric } 1232*fe013be4SDimitry Andric }; 1233*fe013be4SDimitry Andric 1234*fe013be4SDimitry Andric class CommandObjectSourceCacheClear : public CommandObjectParsed { 1235*fe013be4SDimitry Andric public: 1236*fe013be4SDimitry Andric CommandObjectSourceCacheClear(CommandInterpreter &interpreter) 1237*fe013be4SDimitry Andric : CommandObjectParsed(interpreter, "source cache clear", 1238*fe013be4SDimitry Andric "Clear the source code cache.\n", nullptr) {} 1239*fe013be4SDimitry Andric 1240*fe013be4SDimitry Andric ~CommandObjectSourceCacheClear() override = default; 1241*fe013be4SDimitry Andric 1242*fe013be4SDimitry Andric protected: 1243*fe013be4SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 1244*fe013be4SDimitry Andric // Clear the debugger cache. 1245*fe013be4SDimitry Andric SourceManager::SourceFileCache &cache = GetDebugger().GetSourceFileCache(); 1246*fe013be4SDimitry Andric cache.Clear(); 1247*fe013be4SDimitry Andric 1248*fe013be4SDimitry Andric // Clear the process cache. 1249*fe013be4SDimitry Andric if (ProcessSP process_sp = m_exe_ctx.GetProcessSP()) 1250*fe013be4SDimitry Andric process_sp->GetSourceFileCache().Clear(); 1251*fe013be4SDimitry Andric 1252*fe013be4SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 1253*fe013be4SDimitry Andric return result.Succeeded(); 1254*fe013be4SDimitry Andric } 1255*fe013be4SDimitry Andric }; 1256*fe013be4SDimitry Andric 1257*fe013be4SDimitry Andric class CommandObjectSourceCache : public CommandObjectMultiword { 1258*fe013be4SDimitry Andric public: 1259*fe013be4SDimitry Andric CommandObjectSourceCache(CommandInterpreter &interpreter) 1260*fe013be4SDimitry Andric : CommandObjectMultiword(interpreter, "source cache", 1261*fe013be4SDimitry Andric "Commands for managing the source code cache.", 1262*fe013be4SDimitry Andric "source cache <sub-command>") { 1263*fe013be4SDimitry Andric LoadSubCommand( 1264*fe013be4SDimitry Andric "dump", CommandObjectSP(new CommandObjectSourceCacheDump(interpreter))); 1265*fe013be4SDimitry Andric LoadSubCommand("clear", CommandObjectSP(new CommandObjectSourceCacheClear( 1266*fe013be4SDimitry Andric interpreter))); 1267*fe013be4SDimitry Andric } 1268*fe013be4SDimitry Andric 1269*fe013be4SDimitry Andric ~CommandObjectSourceCache() override = default; 1270*fe013be4SDimitry Andric 1271*fe013be4SDimitry Andric private: 1272*fe013be4SDimitry Andric CommandObjectSourceCache(const CommandObjectSourceCache &) = delete; 1273*fe013be4SDimitry Andric const CommandObjectSourceCache & 1274*fe013be4SDimitry Andric operator=(const CommandObjectSourceCache &) = delete; 1275*fe013be4SDimitry Andric }; 1276*fe013be4SDimitry Andric 12770b57cec5SDimitry Andric #pragma mark CommandObjectMultiwordSource 12780b57cec5SDimitry Andric // CommandObjectMultiwordSource 12790b57cec5SDimitry Andric 12800b57cec5SDimitry Andric CommandObjectMultiwordSource::CommandObjectMultiwordSource( 12810b57cec5SDimitry Andric CommandInterpreter &interpreter) 1282480093f4SDimitry Andric : CommandObjectMultiword(interpreter, "source", 1283480093f4SDimitry Andric "Commands for examining " 12840b57cec5SDimitry Andric "source code described by " 12850b57cec5SDimitry Andric "debug information for the " 12860b57cec5SDimitry Andric "current target process.", 12870b57cec5SDimitry Andric "source <subcommand> [<subcommand-options>]") { 12880b57cec5SDimitry Andric LoadSubCommand("info", 12890b57cec5SDimitry Andric CommandObjectSP(new CommandObjectSourceInfo(interpreter))); 12900b57cec5SDimitry Andric LoadSubCommand("list", 12910b57cec5SDimitry Andric CommandObjectSP(new CommandObjectSourceList(interpreter))); 1292*fe013be4SDimitry Andric LoadSubCommand("cache", 1293*fe013be4SDimitry Andric CommandObjectSP(new CommandObjectSourceCache(interpreter))); 12940b57cec5SDimitry Andric } 12950b57cec5SDimitry Andric 12960b57cec5SDimitry Andric CommandObjectMultiwordSource::~CommandObjectMultiwordSource() = default; 1297