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" 170b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 180b57cec5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h" 19e8d8bef9SDimitry Andric #include "lldb/Interpreter/OptionValueFileColonLine.h" 200b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h" 210b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h" 220b57cec5SDimitry Andric #include "lldb/Symbol/Function.h" 230b57cec5SDimitry Andric #include "lldb/Symbol/Symbol.h" 240b57cec5SDimitry Andric #include "lldb/Target/SectionLoadList.h" 250b57cec5SDimitry Andric #include "lldb/Target/StackFrame.h" 260b57cec5SDimitry Andric #include "lldb/Utility/FileSpec.h" 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric using namespace lldb; 290b57cec5SDimitry Andric using namespace lldb_private; 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric #pragma mark CommandObjectSourceInfo 320b57cec5SDimitry Andric // CommandObjectSourceInfo - debug line entries dumping command 339dba64beSDimitry Andric #define LLDB_OPTIONS_source_info 349dba64beSDimitry Andric #include "CommandOptions.inc" 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric class CommandObjectSourceInfo : public CommandObjectParsed { 370b57cec5SDimitry Andric class CommandOptions : public Options { 380b57cec5SDimitry Andric public: 390b57cec5SDimitry Andric CommandOptions() : Options() {} 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric ~CommandOptions() override = default; 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 440b57cec5SDimitry Andric ExecutionContext *execution_context) override { 450b57cec5SDimitry Andric Status error; 460b57cec5SDimitry Andric const int short_option = GetDefinitions()[option_idx].short_option; 470b57cec5SDimitry Andric switch (short_option) { 480b57cec5SDimitry Andric case 'l': 490b57cec5SDimitry Andric if (option_arg.getAsInteger(0, start_line)) 500b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line number: '%s'", 510b57cec5SDimitry Andric option_arg.str().c_str()); 520b57cec5SDimitry Andric break; 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric case 'e': 550b57cec5SDimitry Andric if (option_arg.getAsInteger(0, end_line)) 560b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line number: '%s'", 570b57cec5SDimitry Andric option_arg.str().c_str()); 580b57cec5SDimitry Andric break; 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric case 'c': 610b57cec5SDimitry Andric if (option_arg.getAsInteger(0, num_lines)) 620b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line count: '%s'", 630b57cec5SDimitry Andric option_arg.str().c_str()); 640b57cec5SDimitry Andric break; 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric case 'f': 675ffd83dbSDimitry Andric file_name = std::string(option_arg); 680b57cec5SDimitry Andric break; 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric case 'n': 715ffd83dbSDimitry Andric symbol_name = std::string(option_arg); 720b57cec5SDimitry Andric break; 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric case 'a': { 750b57cec5SDimitry Andric address = OptionArgParser::ToAddress(execution_context, option_arg, 760b57cec5SDimitry Andric LLDB_INVALID_ADDRESS, &error); 770b57cec5SDimitry Andric } break; 780b57cec5SDimitry Andric case 's': 790b57cec5SDimitry Andric modules.push_back(std::string(option_arg)); 800b57cec5SDimitry Andric break; 810b57cec5SDimitry Andric default: 829dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric return error; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 890b57cec5SDimitry Andric file_spec.Clear(); 900b57cec5SDimitry Andric file_name.clear(); 910b57cec5SDimitry Andric symbol_name.clear(); 920b57cec5SDimitry Andric address = LLDB_INVALID_ADDRESS; 930b57cec5SDimitry Andric start_line = 0; 940b57cec5SDimitry Andric end_line = 0; 950b57cec5SDimitry Andric num_lines = 0; 960b57cec5SDimitry Andric modules.clear(); 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1000b57cec5SDimitry Andric return llvm::makeArrayRef(g_source_info_options); 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric // Instance variables to hold the values for command options. 1040b57cec5SDimitry Andric FileSpec file_spec; 1050b57cec5SDimitry Andric std::string file_name; 1060b57cec5SDimitry Andric std::string symbol_name; 1070b57cec5SDimitry Andric lldb::addr_t address; 1080b57cec5SDimitry Andric uint32_t start_line; 1090b57cec5SDimitry Andric uint32_t end_line; 1100b57cec5SDimitry Andric uint32_t num_lines; 111480093f4SDimitry Andric std::vector<std::string> modules; 1120b57cec5SDimitry Andric }; 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric public: 1150b57cec5SDimitry Andric CommandObjectSourceInfo(CommandInterpreter &interpreter) 1160b57cec5SDimitry Andric : CommandObjectParsed( 1170b57cec5SDimitry Andric interpreter, "source info", 1180b57cec5SDimitry Andric "Display source line information for the current target " 1190b57cec5SDimitry Andric "process. Defaults to instruction pointer in current stack " 1200b57cec5SDimitry Andric "frame.", 1210b57cec5SDimitry Andric nullptr, eCommandRequiresTarget), 1220b57cec5SDimitry Andric m_options() {} 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric ~CommandObjectSourceInfo() override = default; 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric protected: 1290b57cec5SDimitry Andric // Dump the line entries in each symbol context. Return the number of entries 1300b57cec5SDimitry Andric // found. If module_list is set, only dump lines contained in one of the 1310b57cec5SDimitry Andric // modules. If file_spec is set, only dump lines in the file. If the 1320b57cec5SDimitry Andric // start_line option was specified, don't print lines less than start_line. 1330b57cec5SDimitry Andric // If the end_line option was specified, don't print lines greater than 1340b57cec5SDimitry Andric // end_line. If the num_lines option was specified, dont print more than 1350b57cec5SDimitry Andric // num_lines entries. 1360b57cec5SDimitry Andric uint32_t DumpLinesInSymbolContexts(Stream &strm, 1370b57cec5SDimitry Andric const SymbolContextList &sc_list, 1380b57cec5SDimitry Andric const ModuleList &module_list, 1390b57cec5SDimitry Andric const FileSpec &file_spec) { 1400b57cec5SDimitry Andric uint32_t start_line = m_options.start_line; 1410b57cec5SDimitry Andric uint32_t end_line = m_options.end_line; 1420b57cec5SDimitry Andric uint32_t num_lines = m_options.num_lines; 1430b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric uint32_t num_matches = 0; 1460b57cec5SDimitry Andric // Dump all the line entries for the file in the list. 1470b57cec5SDimitry Andric ConstString last_module_file_name; 1480b57cec5SDimitry Andric uint32_t num_scs = sc_list.GetSize(); 1490b57cec5SDimitry Andric for (uint32_t i = 0; i < num_scs; ++i) { 1500b57cec5SDimitry Andric SymbolContext sc; 1510b57cec5SDimitry Andric sc_list.GetContextAtIndex(i, sc); 1520b57cec5SDimitry Andric if (sc.comp_unit) { 1530b57cec5SDimitry Andric Module *module = sc.module_sp.get(); 1540b57cec5SDimitry Andric CompileUnit *cu = sc.comp_unit; 1550b57cec5SDimitry Andric const LineEntry &line_entry = sc.line_entry; 1560b57cec5SDimitry Andric assert(module && cu); 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric // Are we looking for specific modules, files or lines? 1590b57cec5SDimitry Andric if (module_list.GetSize() && 1600b57cec5SDimitry Andric module_list.GetIndexForModule(module) == LLDB_INVALID_INDEX32) 1610b57cec5SDimitry Andric continue; 162480093f4SDimitry Andric if (!FileSpec::Match(file_spec, line_entry.file)) 1630b57cec5SDimitry Andric continue; 1640b57cec5SDimitry Andric if (start_line > 0 && line_entry.line < start_line) 1650b57cec5SDimitry Andric continue; 1660b57cec5SDimitry Andric if (end_line > 0 && line_entry.line > end_line) 1670b57cec5SDimitry Andric continue; 1680b57cec5SDimitry Andric if (num_lines > 0 && num_matches > num_lines) 1690b57cec5SDimitry Andric continue; 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric // Print a new header if the module changed. 172480093f4SDimitry Andric ConstString module_file_name = module->GetFileSpec().GetFilename(); 1730b57cec5SDimitry Andric assert(module_file_name); 1740b57cec5SDimitry Andric if (module_file_name != last_module_file_name) { 1750b57cec5SDimitry Andric if (num_matches > 0) 1760b57cec5SDimitry Andric strm << "\n\n"; 1770b57cec5SDimitry Andric strm << "Lines found in module `" << module_file_name << "\n"; 1780b57cec5SDimitry Andric } 1790b57cec5SDimitry Andric // Dump the line entry. 1800b57cec5SDimitry Andric line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu, 1810b57cec5SDimitry Andric target, /*show_address_only=*/false); 1820b57cec5SDimitry Andric strm << "\n"; 1830b57cec5SDimitry Andric last_module_file_name = module_file_name; 1840b57cec5SDimitry Andric num_matches++; 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric return num_matches; 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric // Dump the requested line entries for the file in the compilation unit. 1910b57cec5SDimitry Andric // Return the number of entries found. If module_list is set, only dump lines 1920b57cec5SDimitry Andric // contained in one of the modules. If the start_line option was specified, 1930b57cec5SDimitry Andric // don't print lines less than start_line. If the end_line option was 1940b57cec5SDimitry Andric // specified, don't print lines greater than end_line. If the num_lines 1950b57cec5SDimitry Andric // option was specified, dont print more than num_lines entries. 1960b57cec5SDimitry Andric uint32_t DumpFileLinesInCompUnit(Stream &strm, Module *module, 1970b57cec5SDimitry Andric CompileUnit *cu, const FileSpec &file_spec) { 1980b57cec5SDimitry Andric uint32_t start_line = m_options.start_line; 1990b57cec5SDimitry Andric uint32_t end_line = m_options.end_line; 2000b57cec5SDimitry Andric uint32_t num_lines = m_options.num_lines; 2010b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric uint32_t num_matches = 0; 2040b57cec5SDimitry Andric assert(module); 2050b57cec5SDimitry Andric if (cu) { 2060b57cec5SDimitry Andric assert(file_spec.GetFilename().AsCString()); 2070b57cec5SDimitry Andric bool has_path = (file_spec.GetDirectory().AsCString() != nullptr); 2080b57cec5SDimitry Andric const FileSpecList &cu_file_list = cu->GetSupportFiles(); 2090b57cec5SDimitry Andric size_t file_idx = cu_file_list.FindFileIndex(0, file_spec, has_path); 2100b57cec5SDimitry Andric if (file_idx != UINT32_MAX) { 2110b57cec5SDimitry Andric // Update the file to how it appears in the CU. 2120b57cec5SDimitry Andric const FileSpec &cu_file_spec = 2130b57cec5SDimitry Andric cu_file_list.GetFileSpecAtIndex(file_idx); 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric // Dump all matching lines at or above start_line for the file in the 2160b57cec5SDimitry Andric // CU. 2170b57cec5SDimitry Andric ConstString file_spec_name = file_spec.GetFilename(); 218480093f4SDimitry Andric ConstString module_file_name = module->GetFileSpec().GetFilename(); 2190b57cec5SDimitry Andric bool cu_header_printed = false; 2200b57cec5SDimitry Andric uint32_t line = start_line; 2210b57cec5SDimitry Andric while (true) { 2220b57cec5SDimitry Andric LineEntry line_entry; 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric // Find the lowest index of a line entry with a line equal to or 2250b57cec5SDimitry Andric // higher than 'line'. 2260b57cec5SDimitry Andric uint32_t start_idx = 0; 2270b57cec5SDimitry Andric start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec, 2280b57cec5SDimitry Andric /*exact=*/false, &line_entry); 2290b57cec5SDimitry Andric if (start_idx == UINT32_MAX) 2300b57cec5SDimitry Andric // No more line entries for our file in this CU. 2310b57cec5SDimitry Andric break; 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric if (end_line > 0 && line_entry.line > end_line) 2340b57cec5SDimitry Andric break; 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric // Loop through to find any other entries for this line, dumping 2370b57cec5SDimitry Andric // each. 2380b57cec5SDimitry Andric line = line_entry.line; 2390b57cec5SDimitry Andric do { 2400b57cec5SDimitry Andric num_matches++; 2410b57cec5SDimitry Andric if (num_lines > 0 && num_matches > num_lines) 2420b57cec5SDimitry Andric break; 243480093f4SDimitry Andric assert(cu_file_spec == line_entry.file); 2440b57cec5SDimitry Andric if (!cu_header_printed) { 2450b57cec5SDimitry Andric if (num_matches > 0) 2460b57cec5SDimitry Andric strm << "\n\n"; 2470b57cec5SDimitry Andric strm << "Lines found for file " << file_spec_name 248480093f4SDimitry Andric << " in compilation unit " 249480093f4SDimitry Andric << cu->GetPrimaryFile().GetFilename() << " in `" 2500b57cec5SDimitry Andric << module_file_name << "\n"; 2510b57cec5SDimitry Andric cu_header_printed = true; 2520b57cec5SDimitry Andric } 2530b57cec5SDimitry Andric line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu, 2540b57cec5SDimitry Andric target, /*show_address_only=*/false); 2550b57cec5SDimitry Andric strm << "\n"; 2560b57cec5SDimitry Andric 2570b57cec5SDimitry Andric // Anymore after this one? 2580b57cec5SDimitry Andric start_idx++; 2590b57cec5SDimitry Andric start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec, 2600b57cec5SDimitry Andric /*exact=*/true, &line_entry); 2610b57cec5SDimitry Andric } while (start_idx != UINT32_MAX); 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric // Try the next higher line, starting over at start_idx 0. 2640b57cec5SDimitry Andric line++; 2650b57cec5SDimitry Andric } 2660b57cec5SDimitry Andric } 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric return num_matches; 2690b57cec5SDimitry Andric } 2700b57cec5SDimitry Andric 2710b57cec5SDimitry Andric // Dump the requested line entries for the file in the module. Return the 2720b57cec5SDimitry Andric // number of entries found. If module_list is set, only dump lines contained 2730b57cec5SDimitry Andric // in one of the modules. If the start_line option was specified, don't print 2740b57cec5SDimitry Andric // lines less than start_line. If the end_line option was specified, don't 2750b57cec5SDimitry Andric // print lines greater than end_line. If the num_lines option was specified, 2760b57cec5SDimitry Andric // dont print more than num_lines entries. 2770b57cec5SDimitry Andric uint32_t DumpFileLinesInModule(Stream &strm, Module *module, 2780b57cec5SDimitry Andric const FileSpec &file_spec) { 2790b57cec5SDimitry Andric uint32_t num_matches = 0; 2800b57cec5SDimitry Andric if (module) { 2810b57cec5SDimitry Andric // Look through all the compilation units (CUs) in this module for ones 2820b57cec5SDimitry Andric // that contain lines of code from this source file. 2830b57cec5SDimitry Andric for (size_t i = 0; i < module->GetNumCompileUnits(); i++) { 2840b57cec5SDimitry Andric // Look for a matching source file in this CU. 2850b57cec5SDimitry Andric CompUnitSP cu_sp(module->GetCompileUnitAtIndex(i)); 2860b57cec5SDimitry Andric if (cu_sp) { 2870b57cec5SDimitry Andric num_matches += 2880b57cec5SDimitry Andric DumpFileLinesInCompUnit(strm, module, cu_sp.get(), file_spec); 2890b57cec5SDimitry Andric } 2900b57cec5SDimitry Andric } 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric return num_matches; 2930b57cec5SDimitry Andric } 2940b57cec5SDimitry Andric 2950b57cec5SDimitry Andric // Given an address and a list of modules, append the symbol contexts of all 2960b57cec5SDimitry Andric // line entries containing the address found in the modules and return the 2970b57cec5SDimitry Andric // count of matches. If none is found, return an error in 'error_strm'. 2980b57cec5SDimitry Andric size_t GetSymbolContextsForAddress(const ModuleList &module_list, 2990b57cec5SDimitry Andric lldb::addr_t addr, 3000b57cec5SDimitry Andric SymbolContextList &sc_list, 3010b57cec5SDimitry Andric StreamString &error_strm) { 3020b57cec5SDimitry Andric Address so_addr; 3030b57cec5SDimitry Andric size_t num_matches = 0; 3040b57cec5SDimitry Andric assert(module_list.GetSize() > 0); 3050b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 3060b57cec5SDimitry Andric if (target->GetSectionLoadList().IsEmpty()) { 3070b57cec5SDimitry Andric // The target isn't loaded yet, we need to lookup the file address in all 3080b57cec5SDimitry Andric // modules. Note: the module list option does not apply to addresses. 3090b57cec5SDimitry Andric const size_t num_modules = module_list.GetSize(); 3100b57cec5SDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 3110b57cec5SDimitry Andric ModuleSP module_sp(module_list.GetModuleAtIndex(i)); 3120b57cec5SDimitry Andric if (!module_sp) 3130b57cec5SDimitry Andric continue; 3140b57cec5SDimitry Andric if (module_sp->ResolveFileAddress(addr, so_addr)) { 3150b57cec5SDimitry Andric SymbolContext sc; 3160b57cec5SDimitry Andric sc.Clear(true); 3170b57cec5SDimitry Andric if (module_sp->ResolveSymbolContextForAddress( 3180b57cec5SDimitry Andric so_addr, eSymbolContextEverything, sc) & 3190b57cec5SDimitry Andric eSymbolContextLineEntry) { 3200b57cec5SDimitry Andric sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false); 3210b57cec5SDimitry Andric ++num_matches; 3220b57cec5SDimitry Andric } 3230b57cec5SDimitry Andric } 3240b57cec5SDimitry Andric } 3250b57cec5SDimitry Andric if (num_matches == 0) 3260b57cec5SDimitry Andric error_strm.Printf("Source information for file address 0x%" PRIx64 3270b57cec5SDimitry Andric " not found in any modules.\n", 3280b57cec5SDimitry Andric addr); 3290b57cec5SDimitry Andric } else { 3300b57cec5SDimitry Andric // The target has some things loaded, resolve this address to a compile 3310b57cec5SDimitry Andric // unit + file + line and display 3320b57cec5SDimitry Andric if (target->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) { 3330b57cec5SDimitry Andric ModuleSP module_sp(so_addr.GetModule()); 3340b57cec5SDimitry Andric // Check to make sure this module is in our list. 335480093f4SDimitry Andric if (module_sp && module_list.GetIndexForModule(module_sp.get()) != 3360b57cec5SDimitry Andric LLDB_INVALID_INDEX32) { 3370b57cec5SDimitry Andric SymbolContext sc; 3380b57cec5SDimitry Andric sc.Clear(true); 3390b57cec5SDimitry Andric if (module_sp->ResolveSymbolContextForAddress( 3400b57cec5SDimitry Andric so_addr, eSymbolContextEverything, sc) & 3410b57cec5SDimitry Andric eSymbolContextLineEntry) { 3420b57cec5SDimitry Andric sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false); 3430b57cec5SDimitry Andric ++num_matches; 3440b57cec5SDimitry Andric } else { 3450b57cec5SDimitry Andric StreamString addr_strm; 3460b57cec5SDimitry Andric so_addr.Dump(&addr_strm, nullptr, 3470b57cec5SDimitry Andric Address::DumpStyleModuleWithFileAddress); 3480b57cec5SDimitry Andric error_strm.Printf( 3490b57cec5SDimitry Andric "Address 0x%" PRIx64 " resolves to %s, but there is" 3500b57cec5SDimitry Andric " no source information available for this address.\n", 3510b57cec5SDimitry Andric addr, addr_strm.GetData()); 3520b57cec5SDimitry Andric } 3530b57cec5SDimitry Andric } else { 3540b57cec5SDimitry Andric StreamString addr_strm; 3550b57cec5SDimitry Andric so_addr.Dump(&addr_strm, nullptr, 3560b57cec5SDimitry Andric Address::DumpStyleModuleWithFileAddress); 3570b57cec5SDimitry Andric error_strm.Printf("Address 0x%" PRIx64 3580b57cec5SDimitry Andric " resolves to %s, but it cannot" 3590b57cec5SDimitry Andric " be found in any modules.\n", 3600b57cec5SDimitry Andric addr, addr_strm.GetData()); 3610b57cec5SDimitry Andric } 3620b57cec5SDimitry Andric } else 3630b57cec5SDimitry Andric error_strm.Printf("Unable to resolve address 0x%" PRIx64 ".\n", addr); 3640b57cec5SDimitry Andric } 3650b57cec5SDimitry Andric return num_matches; 3660b57cec5SDimitry Andric } 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric // Dump the line entries found in functions matching the name specified in 3690b57cec5SDimitry Andric // the option. 3700b57cec5SDimitry Andric bool DumpLinesInFunctions(CommandReturnObject &result) { 3710b57cec5SDimitry Andric SymbolContextList sc_list_funcs; 3720b57cec5SDimitry Andric ConstString name(m_options.symbol_name.c_str()); 3730b57cec5SDimitry Andric SymbolContextList sc_list_lines; 3740b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 3750b57cec5SDimitry Andric uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); 3760b57cec5SDimitry Andric 377349cc55cSDimitry Andric ModuleFunctionSearchOptions function_options; 378349cc55cSDimitry Andric function_options.include_symbols = false; 379349cc55cSDimitry Andric function_options.include_inlines = true; 380349cc55cSDimitry Andric 3810b57cec5SDimitry Andric // Note: module_list can't be const& because FindFunctionSymbols isn't 3820b57cec5SDimitry Andric // const. 3830b57cec5SDimitry Andric ModuleList module_list = 3840b57cec5SDimitry Andric (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages(); 385349cc55cSDimitry Andric module_list.FindFunctions(name, eFunctionNameTypeAuto, function_options, 386349cc55cSDimitry Andric sc_list_funcs); 3879dba64beSDimitry Andric size_t num_matches = sc_list_funcs.GetSize(); 3889dba64beSDimitry Andric 3890b57cec5SDimitry Andric if (!num_matches) { 3900b57cec5SDimitry Andric // If we didn't find any functions with that name, try searching for 3910b57cec5SDimitry Andric // symbols that line up exactly with function addresses. 3920b57cec5SDimitry Andric SymbolContextList sc_list_symbols; 393480093f4SDimitry Andric module_list.FindFunctionSymbols(name, eFunctionNameTypeAuto, 394480093f4SDimitry Andric sc_list_symbols); 3959dba64beSDimitry Andric size_t num_symbol_matches = sc_list_symbols.GetSize(); 3960b57cec5SDimitry Andric for (size_t i = 0; i < num_symbol_matches; i++) { 3970b57cec5SDimitry Andric SymbolContext sc; 3980b57cec5SDimitry Andric sc_list_symbols.GetContextAtIndex(i, sc); 3990b57cec5SDimitry Andric if (sc.symbol && sc.symbol->ValueIsAddress()) { 4000b57cec5SDimitry Andric const Address &base_address = sc.symbol->GetAddressRef(); 4010b57cec5SDimitry Andric Function *function = base_address.CalculateSymbolContextFunction(); 4020b57cec5SDimitry Andric if (function) { 4030b57cec5SDimitry Andric sc_list_funcs.Append(SymbolContext(function)); 4040b57cec5SDimitry Andric num_matches++; 4050b57cec5SDimitry Andric } 4060b57cec5SDimitry Andric } 4070b57cec5SDimitry Andric } 4080b57cec5SDimitry Andric } 4090b57cec5SDimitry Andric if (num_matches == 0) { 4100b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find function named \'%s\'.\n", 4110b57cec5SDimitry Andric m_options.symbol_name.c_str()); 4120b57cec5SDimitry Andric return false; 4130b57cec5SDimitry Andric } 4140b57cec5SDimitry Andric for (size_t i = 0; i < num_matches; i++) { 4150b57cec5SDimitry Andric SymbolContext sc; 4160b57cec5SDimitry Andric sc_list_funcs.GetContextAtIndex(i, sc); 4170b57cec5SDimitry Andric bool context_found_for_symbol = false; 4180b57cec5SDimitry Andric // Loop through all the ranges in the function. 4190b57cec5SDimitry Andric AddressRange range; 4200b57cec5SDimitry Andric for (uint32_t r = 0; 4210b57cec5SDimitry Andric sc.GetAddressRange(eSymbolContextEverything, r, 4220b57cec5SDimitry Andric /*use_inline_block_range=*/true, range); 4230b57cec5SDimitry Andric ++r) { 4240b57cec5SDimitry Andric // Append the symbol contexts for each address in the range to 4250b57cec5SDimitry Andric // sc_list_lines. 4260b57cec5SDimitry Andric const Address &base_address = range.GetBaseAddress(); 4270b57cec5SDimitry Andric const addr_t size = range.GetByteSize(); 4280b57cec5SDimitry Andric lldb::addr_t start_addr = base_address.GetLoadAddress(target); 4290b57cec5SDimitry Andric if (start_addr == LLDB_INVALID_ADDRESS) 4300b57cec5SDimitry Andric start_addr = base_address.GetFileAddress(); 4310b57cec5SDimitry Andric lldb::addr_t end_addr = start_addr + size; 4320b57cec5SDimitry Andric for (lldb::addr_t addr = start_addr; addr < end_addr; 4330b57cec5SDimitry Andric addr += addr_byte_size) { 4340b57cec5SDimitry Andric StreamString error_strm; 4350b57cec5SDimitry Andric if (!GetSymbolContextsForAddress(module_list, addr, sc_list_lines, 4360b57cec5SDimitry Andric error_strm)) 4370b57cec5SDimitry Andric result.AppendWarningWithFormat("in symbol '%s': %s", 4380b57cec5SDimitry Andric sc.GetFunctionName().AsCString(), 4390b57cec5SDimitry Andric error_strm.GetData()); 4400b57cec5SDimitry Andric else 4410b57cec5SDimitry Andric context_found_for_symbol = true; 4420b57cec5SDimitry Andric } 4430b57cec5SDimitry Andric } 4440b57cec5SDimitry Andric if (!context_found_for_symbol) 4450b57cec5SDimitry Andric result.AppendWarningWithFormat("Unable to find line information" 4460b57cec5SDimitry Andric " for matching symbol '%s'.\n", 4470b57cec5SDimitry Andric sc.GetFunctionName().AsCString()); 4480b57cec5SDimitry Andric } 4490b57cec5SDimitry Andric if (sc_list_lines.GetSize() == 0) { 4500b57cec5SDimitry Andric result.AppendErrorWithFormat("No line information could be found" 4510b57cec5SDimitry Andric " for any symbols matching '%s'.\n", 4520b57cec5SDimitry Andric name.AsCString()); 4530b57cec5SDimitry Andric return false; 4540b57cec5SDimitry Andric } 4550b57cec5SDimitry Andric FileSpec file_spec; 4560b57cec5SDimitry Andric if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list_lines, 4570b57cec5SDimitry Andric module_list, file_spec)) { 4580b57cec5SDimitry Andric result.AppendErrorWithFormat( 4590b57cec5SDimitry Andric "Unable to dump line information for symbol '%s'.\n", 4600b57cec5SDimitry Andric name.AsCString()); 4610b57cec5SDimitry Andric return false; 4620b57cec5SDimitry Andric } 4630b57cec5SDimitry Andric return true; 4640b57cec5SDimitry Andric } 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric // Dump the line entries found for the address specified in the option. 4670b57cec5SDimitry Andric bool DumpLinesForAddress(CommandReturnObject &result) { 4680b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 4690b57cec5SDimitry Andric SymbolContextList sc_list; 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric StreamString error_strm; 4720b57cec5SDimitry Andric if (!GetSymbolContextsForAddress(target->GetImages(), m_options.address, 4730b57cec5SDimitry Andric sc_list, error_strm)) { 4740b57cec5SDimitry Andric result.AppendErrorWithFormat("%s.\n", error_strm.GetData()); 4750b57cec5SDimitry Andric return false; 4760b57cec5SDimitry Andric } 4770b57cec5SDimitry Andric ModuleList module_list; 4780b57cec5SDimitry Andric FileSpec file_spec; 4790b57cec5SDimitry Andric if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list, 4800b57cec5SDimitry Andric module_list, file_spec)) { 4810b57cec5SDimitry Andric result.AppendErrorWithFormat("No modules contain load address 0x%" PRIx64 4820b57cec5SDimitry Andric ".\n", 4830b57cec5SDimitry Andric m_options.address); 4840b57cec5SDimitry Andric return false; 4850b57cec5SDimitry Andric } 4860b57cec5SDimitry Andric return true; 4870b57cec5SDimitry Andric } 4880b57cec5SDimitry Andric 4890b57cec5SDimitry Andric // Dump the line entries found in the file specified in the option. 4900b57cec5SDimitry Andric bool DumpLinesForFile(CommandReturnObject &result) { 4910b57cec5SDimitry Andric FileSpec file_spec(m_options.file_name); 4920b57cec5SDimitry Andric const char *filename = m_options.file_name.c_str(); 4930b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 4940b57cec5SDimitry Andric const ModuleList &module_list = 4950b57cec5SDimitry Andric (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages(); 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric bool displayed_something = false; 4980b57cec5SDimitry Andric const size_t num_modules = module_list.GetSize(); 4990b57cec5SDimitry Andric for (uint32_t i = 0; i < num_modules; ++i) { 5000b57cec5SDimitry Andric // Dump lines for this module. 5010b57cec5SDimitry Andric Module *module = module_list.GetModulePointerAtIndex(i); 5020b57cec5SDimitry Andric assert(module); 5030b57cec5SDimitry Andric if (DumpFileLinesInModule(result.GetOutputStream(), module, file_spec)) 5040b57cec5SDimitry Andric displayed_something = true; 5050b57cec5SDimitry Andric } 5060b57cec5SDimitry Andric if (!displayed_something) { 5070b57cec5SDimitry Andric result.AppendErrorWithFormat("No source filenames matched '%s'.\n", 5080b57cec5SDimitry Andric filename); 5090b57cec5SDimitry Andric return false; 5100b57cec5SDimitry Andric } 5110b57cec5SDimitry Andric return true; 5120b57cec5SDimitry Andric } 5130b57cec5SDimitry Andric 5140b57cec5SDimitry Andric // Dump the line entries for the current frame. 5150b57cec5SDimitry Andric bool DumpLinesForFrame(CommandReturnObject &result) { 5160b57cec5SDimitry Andric StackFrame *cur_frame = m_exe_ctx.GetFramePtr(); 5170b57cec5SDimitry Andric if (cur_frame == nullptr) { 5180b57cec5SDimitry Andric result.AppendError( 5190b57cec5SDimitry Andric "No selected frame to use to find the default source."); 5200b57cec5SDimitry Andric return false; 5210b57cec5SDimitry Andric } else if (!cur_frame->HasDebugInformation()) { 5220b57cec5SDimitry Andric result.AppendError("No debug info for the selected frame."); 5230b57cec5SDimitry Andric return false; 5240b57cec5SDimitry Andric } else { 5250b57cec5SDimitry Andric const SymbolContext &sc = 5260b57cec5SDimitry Andric cur_frame->GetSymbolContext(eSymbolContextLineEntry); 5270b57cec5SDimitry Andric SymbolContextList sc_list; 5280b57cec5SDimitry Andric sc_list.Append(sc); 5290b57cec5SDimitry Andric ModuleList module_list; 5300b57cec5SDimitry Andric FileSpec file_spec; 5310b57cec5SDimitry Andric if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list, 5320b57cec5SDimitry Andric module_list, file_spec)) { 5330b57cec5SDimitry Andric result.AppendError( 5340b57cec5SDimitry Andric "No source line info available for the selected frame."); 5350b57cec5SDimitry Andric return false; 5360b57cec5SDimitry Andric } 5370b57cec5SDimitry Andric } 5380b57cec5SDimitry Andric return true; 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 5420b57cec5SDimitry Andric const size_t argc = command.GetArgumentCount(); 5430b57cec5SDimitry Andric 5440b57cec5SDimitry Andric if (argc != 0) { 5450b57cec5SDimitry Andric result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", 5460b57cec5SDimitry Andric GetCommandName().str().c_str()); 5470b57cec5SDimitry Andric return false; 5480b57cec5SDimitry Andric } 5490b57cec5SDimitry Andric 5500b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 5510b57cec5SDimitry Andric if (target == nullptr) { 5520b57cec5SDimitry Andric target = GetDebugger().GetSelectedTarget().get(); 5530b57cec5SDimitry Andric if (target == nullptr) { 5540b57cec5SDimitry Andric result.AppendError("invalid target, create a debug target using the " 5550b57cec5SDimitry Andric "'target create' command."); 5560b57cec5SDimitry Andric return false; 5570b57cec5SDimitry Andric } 5580b57cec5SDimitry Andric } 5590b57cec5SDimitry Andric 5600b57cec5SDimitry Andric uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); 5610b57cec5SDimitry Andric result.GetOutputStream().SetAddressByteSize(addr_byte_size); 5620b57cec5SDimitry Andric result.GetErrorStream().SetAddressByteSize(addr_byte_size); 5630b57cec5SDimitry Andric 5640b57cec5SDimitry Andric // Collect the list of modules to search. 5650b57cec5SDimitry Andric m_module_list.Clear(); 5660b57cec5SDimitry Andric if (!m_options.modules.empty()) { 5670b57cec5SDimitry Andric for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) { 5680b57cec5SDimitry Andric FileSpec module_file_spec(m_options.modules[i]); 5690b57cec5SDimitry Andric if (module_file_spec) { 5700b57cec5SDimitry Andric ModuleSpec module_spec(module_file_spec); 5719dba64beSDimitry Andric target->GetImages().FindModules(module_spec, m_module_list); 5729dba64beSDimitry Andric if (m_module_list.IsEmpty()) 5730b57cec5SDimitry Andric result.AppendWarningWithFormat("No module found for '%s'.\n", 5740b57cec5SDimitry Andric m_options.modules[i].c_str()); 5750b57cec5SDimitry Andric } 5760b57cec5SDimitry Andric } 5770b57cec5SDimitry Andric if (!m_module_list.GetSize()) { 5780b57cec5SDimitry Andric result.AppendError("No modules match the input."); 5790b57cec5SDimitry Andric return false; 5800b57cec5SDimitry Andric } 5810b57cec5SDimitry Andric } else if (target->GetImages().GetSize() == 0) { 5820b57cec5SDimitry Andric result.AppendError("The target has no associated executable images."); 5830b57cec5SDimitry Andric return false; 5840b57cec5SDimitry Andric } 5850b57cec5SDimitry Andric 5860b57cec5SDimitry Andric // Check the arguments to see what lines we should dump. 5870b57cec5SDimitry Andric if (!m_options.symbol_name.empty()) { 5880b57cec5SDimitry Andric // Print lines for symbol. 5890b57cec5SDimitry Andric if (DumpLinesInFunctions(result)) 5900b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 5910b57cec5SDimitry Andric else 5920b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 5930b57cec5SDimitry Andric } else if (m_options.address != LLDB_INVALID_ADDRESS) { 5940b57cec5SDimitry Andric // Print lines for an address. 5950b57cec5SDimitry Andric if (DumpLinesForAddress(result)) 5960b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 5970b57cec5SDimitry Andric else 5980b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 5990b57cec5SDimitry Andric } else if (!m_options.file_name.empty()) { 6000b57cec5SDimitry Andric // Dump lines for a file. 6010b57cec5SDimitry Andric if (DumpLinesForFile(result)) 6020b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 6030b57cec5SDimitry Andric else 6040b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 6050b57cec5SDimitry Andric } else { 6060b57cec5SDimitry Andric // Dump the line for the current frame. 6070b57cec5SDimitry Andric if (DumpLinesForFrame(result)) 6080b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 6090b57cec5SDimitry Andric else 6100b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 6110b57cec5SDimitry Andric } 6120b57cec5SDimitry Andric return result.Succeeded(); 6130b57cec5SDimitry Andric } 6140b57cec5SDimitry Andric 6150b57cec5SDimitry Andric CommandOptions m_options; 6160b57cec5SDimitry Andric ModuleList m_module_list; 6170b57cec5SDimitry Andric }; 6180b57cec5SDimitry Andric 6190b57cec5SDimitry Andric #pragma mark CommandObjectSourceList 6200b57cec5SDimitry Andric // CommandObjectSourceList 6219dba64beSDimitry Andric #define LLDB_OPTIONS_source_list 6229dba64beSDimitry Andric #include "CommandOptions.inc" 6230b57cec5SDimitry Andric 6240b57cec5SDimitry Andric class CommandObjectSourceList : public CommandObjectParsed { 6250b57cec5SDimitry Andric class CommandOptions : public Options { 6260b57cec5SDimitry Andric public: 6270b57cec5SDimitry Andric CommandOptions() : Options() {} 6280b57cec5SDimitry Andric 6290b57cec5SDimitry Andric ~CommandOptions() override = default; 6300b57cec5SDimitry Andric 6310b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 6320b57cec5SDimitry Andric ExecutionContext *execution_context) override { 6330b57cec5SDimitry Andric Status error; 6340b57cec5SDimitry Andric const int short_option = GetDefinitions()[option_idx].short_option; 6350b57cec5SDimitry Andric switch (short_option) { 6360b57cec5SDimitry Andric case 'l': 6370b57cec5SDimitry Andric if (option_arg.getAsInteger(0, start_line)) 6380b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line number: '%s'", 6390b57cec5SDimitry Andric option_arg.str().c_str()); 6400b57cec5SDimitry Andric break; 6410b57cec5SDimitry Andric 6420b57cec5SDimitry Andric case 'c': 6430b57cec5SDimitry Andric if (option_arg.getAsInteger(0, num_lines)) 6440b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line count: '%s'", 6450b57cec5SDimitry Andric option_arg.str().c_str()); 6460b57cec5SDimitry Andric break; 6470b57cec5SDimitry Andric 6480b57cec5SDimitry Andric case 'f': 6495ffd83dbSDimitry Andric file_name = std::string(option_arg); 6500b57cec5SDimitry Andric break; 6510b57cec5SDimitry Andric 6520b57cec5SDimitry Andric case 'n': 6535ffd83dbSDimitry Andric symbol_name = std::string(option_arg); 6540b57cec5SDimitry Andric break; 6550b57cec5SDimitry Andric 6560b57cec5SDimitry Andric case 'a': { 6570b57cec5SDimitry Andric address = OptionArgParser::ToAddress(execution_context, option_arg, 6580b57cec5SDimitry Andric LLDB_INVALID_ADDRESS, &error); 6590b57cec5SDimitry Andric } break; 6600b57cec5SDimitry Andric case 's': 6610b57cec5SDimitry Andric modules.push_back(std::string(option_arg)); 6620b57cec5SDimitry Andric break; 6630b57cec5SDimitry Andric 6640b57cec5SDimitry Andric case 'b': 6650b57cec5SDimitry Andric show_bp_locs = true; 6660b57cec5SDimitry Andric break; 6670b57cec5SDimitry Andric case 'r': 6680b57cec5SDimitry Andric reverse = true; 6690b57cec5SDimitry Andric break; 670e8d8bef9SDimitry Andric case 'y': 671e8d8bef9SDimitry Andric { 672e8d8bef9SDimitry Andric OptionValueFileColonLine value; 673e8d8bef9SDimitry Andric Status fcl_err = value.SetValueFromString(option_arg); 674e8d8bef9SDimitry Andric if (!fcl_err.Success()) { 675e8d8bef9SDimitry Andric error.SetErrorStringWithFormat( 676e8d8bef9SDimitry Andric "Invalid value for file:line specifier: %s", 677e8d8bef9SDimitry Andric fcl_err.AsCString()); 678e8d8bef9SDimitry Andric } else { 679e8d8bef9SDimitry Andric file_name = value.GetFileSpec().GetPath(); 680e8d8bef9SDimitry Andric start_line = value.GetLineNumber(); 681e8d8bef9SDimitry Andric // I don't see anything useful to do with a column number, but I don't 682e8d8bef9SDimitry Andric // want to complain since someone may well have cut and pasted a 683e8d8bef9SDimitry Andric // listing from somewhere that included a column. 684e8d8bef9SDimitry Andric } 685e8d8bef9SDimitry Andric } break; 6860b57cec5SDimitry Andric default: 6879dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 6880b57cec5SDimitry Andric } 6890b57cec5SDimitry Andric 6900b57cec5SDimitry Andric return error; 6910b57cec5SDimitry Andric } 6920b57cec5SDimitry Andric 6930b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 6940b57cec5SDimitry Andric file_spec.Clear(); 6950b57cec5SDimitry Andric file_name.clear(); 6960b57cec5SDimitry Andric symbol_name.clear(); 6970b57cec5SDimitry Andric address = LLDB_INVALID_ADDRESS; 6980b57cec5SDimitry Andric start_line = 0; 6990b57cec5SDimitry Andric num_lines = 0; 7000b57cec5SDimitry Andric show_bp_locs = false; 7010b57cec5SDimitry Andric reverse = false; 7020b57cec5SDimitry Andric modules.clear(); 7030b57cec5SDimitry Andric } 7040b57cec5SDimitry Andric 7050b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 7060b57cec5SDimitry Andric return llvm::makeArrayRef(g_source_list_options); 7070b57cec5SDimitry Andric } 7080b57cec5SDimitry Andric 7090b57cec5SDimitry Andric // Instance variables to hold the values for command options. 7100b57cec5SDimitry Andric FileSpec file_spec; 7110b57cec5SDimitry Andric std::string file_name; 7120b57cec5SDimitry Andric std::string symbol_name; 7130b57cec5SDimitry Andric lldb::addr_t address; 7140b57cec5SDimitry Andric uint32_t start_line; 7150b57cec5SDimitry Andric uint32_t num_lines; 716480093f4SDimitry Andric std::vector<std::string> modules; 7170b57cec5SDimitry Andric bool show_bp_locs; 7180b57cec5SDimitry Andric bool reverse; 7190b57cec5SDimitry Andric }; 7200b57cec5SDimitry Andric 7210b57cec5SDimitry Andric public: 7220b57cec5SDimitry Andric CommandObjectSourceList(CommandInterpreter &interpreter) 7230b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "source list", 7240b57cec5SDimitry Andric "Display source code for the current target " 7250b57cec5SDimitry Andric "process as specified by options.", 7260b57cec5SDimitry Andric nullptr, eCommandRequiresTarget), 7270b57cec5SDimitry Andric m_options() {} 7280b57cec5SDimitry Andric 7290b57cec5SDimitry Andric ~CommandObjectSourceList() override = default; 7300b57cec5SDimitry Andric 7310b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 7320b57cec5SDimitry Andric 7330b57cec5SDimitry Andric const char *GetRepeatCommand(Args ¤t_command_args, 7340b57cec5SDimitry Andric uint32_t index) override { 7350b57cec5SDimitry Andric // This is kind of gross, but the command hasn't been parsed yet so we 7360b57cec5SDimitry Andric // can't look at the option values for this invocation... I have to scan 7370b57cec5SDimitry Andric // the arguments directly. 7380b57cec5SDimitry Andric auto iter = 7390b57cec5SDimitry Andric llvm::find_if(current_command_args, [](const Args::ArgEntry &e) { 7409dba64beSDimitry Andric return e.ref() == "-r" || e.ref() == "--reverse"; 7410b57cec5SDimitry Andric }); 7420b57cec5SDimitry Andric if (iter == current_command_args.end()) 7430b57cec5SDimitry Andric return m_cmd_name.c_str(); 7440b57cec5SDimitry Andric 7450b57cec5SDimitry Andric if (m_reverse_name.empty()) { 7460b57cec5SDimitry Andric m_reverse_name = m_cmd_name; 7470b57cec5SDimitry Andric m_reverse_name.append(" -r"); 7480b57cec5SDimitry Andric } 7490b57cec5SDimitry Andric return m_reverse_name.c_str(); 7500b57cec5SDimitry Andric } 7510b57cec5SDimitry Andric 7520b57cec5SDimitry Andric protected: 7530b57cec5SDimitry Andric struct SourceInfo { 7540b57cec5SDimitry Andric ConstString function; 7550b57cec5SDimitry Andric LineEntry line_entry; 7560b57cec5SDimitry Andric 7570b57cec5SDimitry Andric SourceInfo(ConstString name, const LineEntry &line_entry) 7580b57cec5SDimitry Andric : function(name), line_entry(line_entry) {} 7590b57cec5SDimitry Andric 7600b57cec5SDimitry Andric SourceInfo() : function(), line_entry() {} 7610b57cec5SDimitry Andric 7620b57cec5SDimitry Andric bool IsValid() const { return (bool)function && line_entry.IsValid(); } 7630b57cec5SDimitry Andric 7640b57cec5SDimitry Andric bool operator==(const SourceInfo &rhs) const { 7650b57cec5SDimitry Andric return function == rhs.function && 7660b57cec5SDimitry Andric line_entry.original_file == rhs.line_entry.original_file && 7670b57cec5SDimitry Andric line_entry.line == rhs.line_entry.line; 7680b57cec5SDimitry Andric } 7690b57cec5SDimitry Andric 7700b57cec5SDimitry Andric bool operator!=(const SourceInfo &rhs) const { 7710b57cec5SDimitry Andric return function != rhs.function || 7720b57cec5SDimitry Andric line_entry.original_file != rhs.line_entry.original_file || 7730b57cec5SDimitry Andric line_entry.line != rhs.line_entry.line; 7740b57cec5SDimitry Andric } 7750b57cec5SDimitry Andric 7760b57cec5SDimitry Andric bool operator<(const SourceInfo &rhs) const { 7770b57cec5SDimitry Andric if (function.GetCString() < rhs.function.GetCString()) 7780b57cec5SDimitry Andric return true; 7790b57cec5SDimitry Andric if (line_entry.file.GetDirectory().GetCString() < 7800b57cec5SDimitry Andric rhs.line_entry.file.GetDirectory().GetCString()) 7810b57cec5SDimitry Andric return true; 7820b57cec5SDimitry Andric if (line_entry.file.GetFilename().GetCString() < 7830b57cec5SDimitry Andric rhs.line_entry.file.GetFilename().GetCString()) 7840b57cec5SDimitry Andric return true; 7850b57cec5SDimitry Andric if (line_entry.line < rhs.line_entry.line) 7860b57cec5SDimitry Andric return true; 7870b57cec5SDimitry Andric return false; 7880b57cec5SDimitry Andric } 7890b57cec5SDimitry Andric }; 7900b57cec5SDimitry Andric 7910b57cec5SDimitry Andric size_t DisplayFunctionSource(const SymbolContext &sc, SourceInfo &source_info, 7920b57cec5SDimitry Andric CommandReturnObject &result) { 7930b57cec5SDimitry Andric if (!source_info.IsValid()) { 7940b57cec5SDimitry Andric source_info.function = sc.GetFunctionName(); 7950b57cec5SDimitry Andric source_info.line_entry = sc.GetFunctionStartLineEntry(); 7960b57cec5SDimitry Andric } 7970b57cec5SDimitry Andric 7980b57cec5SDimitry Andric if (sc.function) { 7990b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 8000b57cec5SDimitry Andric 8010b57cec5SDimitry Andric FileSpec start_file; 8020b57cec5SDimitry Andric uint32_t start_line; 8030b57cec5SDimitry Andric uint32_t end_line; 8040b57cec5SDimitry Andric FileSpec end_file; 8050b57cec5SDimitry Andric 8060b57cec5SDimitry Andric if (sc.block == nullptr) { 8070b57cec5SDimitry Andric // Not an inlined function 8080b57cec5SDimitry Andric sc.function->GetStartLineSourceInfo(start_file, start_line); 8090b57cec5SDimitry Andric if (start_line == 0) { 8100b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find line information for " 8110b57cec5SDimitry Andric "start of function: \"%s\".\n", 8120b57cec5SDimitry Andric source_info.function.GetCString()); 8130b57cec5SDimitry Andric return 0; 8140b57cec5SDimitry Andric } 8150b57cec5SDimitry Andric sc.function->GetEndLineSourceInfo(end_file, end_line); 8160b57cec5SDimitry Andric } else { 8170b57cec5SDimitry Andric // We have an inlined function 8180b57cec5SDimitry Andric start_file = source_info.line_entry.file; 8190b57cec5SDimitry Andric start_line = source_info.line_entry.line; 8200b57cec5SDimitry Andric end_line = start_line + m_options.num_lines; 8210b57cec5SDimitry Andric } 8220b57cec5SDimitry Andric 8230b57cec5SDimitry Andric // This is a little hacky, but the first line table entry for a function 8240b57cec5SDimitry Andric // points to the "{" that starts the function block. It would be nice to 8250b57cec5SDimitry Andric // actually get the function declaration in there too. So back up a bit, 8260b57cec5SDimitry Andric // but not further than what you're going to display. 8270b57cec5SDimitry Andric uint32_t extra_lines; 8280b57cec5SDimitry Andric if (m_options.num_lines >= 10) 8290b57cec5SDimitry Andric extra_lines = 5; 8300b57cec5SDimitry Andric else 8310b57cec5SDimitry Andric extra_lines = m_options.num_lines / 2; 8320b57cec5SDimitry Andric uint32_t line_no; 8330b57cec5SDimitry Andric if (start_line <= extra_lines) 8340b57cec5SDimitry Andric line_no = 1; 8350b57cec5SDimitry Andric else 8360b57cec5SDimitry Andric line_no = start_line - extra_lines; 8370b57cec5SDimitry Andric 8380b57cec5SDimitry Andric // For fun, if the function is shorter than the number of lines we're 8390b57cec5SDimitry Andric // supposed to display, only display the function... 8400b57cec5SDimitry Andric if (end_line != 0) { 8410b57cec5SDimitry Andric if (m_options.num_lines > end_line - line_no) 8420b57cec5SDimitry Andric m_options.num_lines = end_line - line_no + extra_lines; 8430b57cec5SDimitry Andric } 8440b57cec5SDimitry Andric 8450b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 8460b57cec5SDimitry Andric 8470b57cec5SDimitry Andric if (m_options.show_bp_locs) { 8480b57cec5SDimitry Andric const bool show_inlines = true; 8490b57cec5SDimitry Andric m_breakpoint_locations.Reset(start_file, 0, show_inlines); 8500b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 8510b57cec5SDimitry Andric m_exe_ctx.GetTargetSP()); 8520b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 8530b57cec5SDimitry Andric } 8540b57cec5SDimitry Andric 8550b57cec5SDimitry Andric result.AppendMessageWithFormat("File: %s\n", 8560b57cec5SDimitry Andric start_file.GetPath().c_str()); 8570b57cec5SDimitry Andric // We don't care about the column here. 8580b57cec5SDimitry Andric const uint32_t column = 0; 8590b57cec5SDimitry Andric return target->GetSourceManager().DisplaySourceLinesWithLineNumbers( 8600b57cec5SDimitry Andric start_file, line_no, column, 0, m_options.num_lines, "", 8610b57cec5SDimitry Andric &result.GetOutputStream(), GetBreakpointLocations()); 8620b57cec5SDimitry Andric } else { 8630b57cec5SDimitry Andric result.AppendErrorWithFormat( 8640b57cec5SDimitry Andric "Could not find function info for: \"%s\".\n", 8650b57cec5SDimitry Andric m_options.symbol_name.c_str()); 8660b57cec5SDimitry Andric } 8670b57cec5SDimitry Andric return 0; 8680b57cec5SDimitry Andric } 8690b57cec5SDimitry Andric 8700b57cec5SDimitry Andric // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols 8710b57cec5SDimitry Andric // functions "take a possibly empty vector of strings which are names of 8720b57cec5SDimitry Andric // modules, and run the two search functions on the subset of the full module 8730b57cec5SDimitry Andric // list that matches the strings in the input vector". If we wanted to put 8740b57cec5SDimitry Andric // these somewhere, there should probably be a module-filter-list that can be 8750b57cec5SDimitry Andric // passed to the various ModuleList::Find* calls, which would either be a 8760b57cec5SDimitry Andric // vector of string names or a ModuleSpecList. 8779dba64beSDimitry Andric void FindMatchingFunctions(Target *target, ConstString name, 8780b57cec5SDimitry Andric SymbolContextList &sc_list) { 8790b57cec5SDimitry Andric // Displaying the source for a symbol: 8800b57cec5SDimitry Andric if (m_options.num_lines == 0) 8810b57cec5SDimitry Andric m_options.num_lines = 10; 8820b57cec5SDimitry Andric 883349cc55cSDimitry Andric ModuleFunctionSearchOptions function_options; 884349cc55cSDimitry Andric function_options.include_symbols = true; 885349cc55cSDimitry Andric function_options.include_inlines = false; 886349cc55cSDimitry Andric 8870b57cec5SDimitry Andric const size_t num_modules = m_options.modules.size(); 8880b57cec5SDimitry Andric if (num_modules > 0) { 8890b57cec5SDimitry Andric ModuleList matching_modules; 8900b57cec5SDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 8910b57cec5SDimitry Andric FileSpec module_file_spec(m_options.modules[i]); 8920b57cec5SDimitry Andric if (module_file_spec) { 8930b57cec5SDimitry Andric ModuleSpec module_spec(module_file_spec); 8940b57cec5SDimitry Andric matching_modules.Clear(); 8950b57cec5SDimitry Andric target->GetImages().FindModules(module_spec, matching_modules); 896349cc55cSDimitry Andric 897480093f4SDimitry Andric matching_modules.FindFunctions(name, eFunctionNameTypeAuto, 898349cc55cSDimitry Andric function_options, sc_list); 8990b57cec5SDimitry Andric } 9000b57cec5SDimitry Andric } 9010b57cec5SDimitry Andric } else { 9029dba64beSDimitry Andric target->GetImages().FindFunctions(name, eFunctionNameTypeAuto, 903349cc55cSDimitry Andric function_options, sc_list); 9040b57cec5SDimitry Andric } 9050b57cec5SDimitry Andric } 9060b57cec5SDimitry Andric 9079dba64beSDimitry Andric void FindMatchingFunctionSymbols(Target *target, ConstString name, 9080b57cec5SDimitry Andric SymbolContextList &sc_list) { 9090b57cec5SDimitry Andric const size_t num_modules = m_options.modules.size(); 9100b57cec5SDimitry Andric if (num_modules > 0) { 9110b57cec5SDimitry Andric ModuleList matching_modules; 9120b57cec5SDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 9130b57cec5SDimitry Andric FileSpec module_file_spec(m_options.modules[i]); 9140b57cec5SDimitry Andric if (module_file_spec) { 9150b57cec5SDimitry Andric ModuleSpec module_spec(module_file_spec); 9160b57cec5SDimitry Andric matching_modules.Clear(); 9170b57cec5SDimitry Andric target->GetImages().FindModules(module_spec, matching_modules); 9189dba64beSDimitry Andric matching_modules.FindFunctionSymbols(name, eFunctionNameTypeAuto, 9199dba64beSDimitry Andric sc_list); 9200b57cec5SDimitry Andric } 9210b57cec5SDimitry Andric } 9220b57cec5SDimitry Andric } else { 9239dba64beSDimitry Andric target->GetImages().FindFunctionSymbols(name, eFunctionNameTypeAuto, 9249dba64beSDimitry Andric sc_list); 9250b57cec5SDimitry Andric } 9260b57cec5SDimitry Andric } 9270b57cec5SDimitry Andric 9280b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 9290b57cec5SDimitry Andric const size_t argc = command.GetArgumentCount(); 9300b57cec5SDimitry Andric 9310b57cec5SDimitry Andric if (argc != 0) { 9320b57cec5SDimitry Andric result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", 9330b57cec5SDimitry Andric GetCommandName().str().c_str()); 9340b57cec5SDimitry Andric return false; 9350b57cec5SDimitry Andric } 9360b57cec5SDimitry Andric 9370b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 9380b57cec5SDimitry Andric 9390b57cec5SDimitry Andric if (!m_options.symbol_name.empty()) { 9400b57cec5SDimitry Andric SymbolContextList sc_list; 9410b57cec5SDimitry Andric ConstString name(m_options.symbol_name.c_str()); 9420b57cec5SDimitry Andric 9430b57cec5SDimitry Andric // Displaying the source for a symbol. Search for function named name. 9449dba64beSDimitry Andric FindMatchingFunctions(target, name, sc_list); 9459dba64beSDimitry Andric size_t num_matches = sc_list.GetSize(); 9460b57cec5SDimitry Andric if (!num_matches) { 9470b57cec5SDimitry Andric // If we didn't find any functions with that name, try searching for 9480b57cec5SDimitry Andric // symbols that line up exactly with function addresses. 9490b57cec5SDimitry Andric SymbolContextList sc_list_symbols; 9500b57cec5SDimitry Andric FindMatchingFunctionSymbols(target, name, sc_list_symbols); 9519dba64beSDimitry Andric size_t num_symbol_matches = sc_list_symbols.GetSize(); 9529dba64beSDimitry Andric 9530b57cec5SDimitry Andric for (size_t i = 0; i < num_symbol_matches; i++) { 9540b57cec5SDimitry Andric SymbolContext sc; 9550b57cec5SDimitry Andric sc_list_symbols.GetContextAtIndex(i, sc); 9560b57cec5SDimitry Andric if (sc.symbol && sc.symbol->ValueIsAddress()) { 9570b57cec5SDimitry Andric const Address &base_address = sc.symbol->GetAddressRef(); 9580b57cec5SDimitry Andric Function *function = base_address.CalculateSymbolContextFunction(); 9590b57cec5SDimitry Andric if (function) { 9600b57cec5SDimitry Andric sc_list.Append(SymbolContext(function)); 9610b57cec5SDimitry Andric num_matches++; 9620b57cec5SDimitry Andric break; 9630b57cec5SDimitry Andric } 9640b57cec5SDimitry Andric } 9650b57cec5SDimitry Andric } 9660b57cec5SDimitry Andric } 9670b57cec5SDimitry Andric 9680b57cec5SDimitry Andric if (num_matches == 0) { 9690b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find function named: \"%s\".\n", 9700b57cec5SDimitry Andric m_options.symbol_name.c_str()); 9710b57cec5SDimitry Andric return false; 9720b57cec5SDimitry Andric } 9730b57cec5SDimitry Andric 9740b57cec5SDimitry Andric if (num_matches > 1) { 9750b57cec5SDimitry Andric std::set<SourceInfo> source_match_set; 9760b57cec5SDimitry Andric 9770b57cec5SDimitry Andric bool displayed_something = false; 9780b57cec5SDimitry Andric for (size_t i = 0; i < num_matches; i++) { 9790b57cec5SDimitry Andric SymbolContext sc; 9800b57cec5SDimitry Andric sc_list.GetContextAtIndex(i, sc); 9810b57cec5SDimitry Andric SourceInfo source_info(sc.GetFunctionName(), 9820b57cec5SDimitry Andric sc.GetFunctionStartLineEntry()); 9830b57cec5SDimitry Andric 9840b57cec5SDimitry Andric if (source_info.IsValid()) { 9850b57cec5SDimitry Andric if (source_match_set.find(source_info) == source_match_set.end()) { 9860b57cec5SDimitry Andric source_match_set.insert(source_info); 9870b57cec5SDimitry Andric if (DisplayFunctionSource(sc, source_info, result)) 9880b57cec5SDimitry Andric displayed_something = true; 9890b57cec5SDimitry Andric } 9900b57cec5SDimitry Andric } 9910b57cec5SDimitry Andric } 9920b57cec5SDimitry Andric 9930b57cec5SDimitry Andric if (displayed_something) 9940b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 9950b57cec5SDimitry Andric else 9960b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 9970b57cec5SDimitry Andric } else { 9980b57cec5SDimitry Andric SymbolContext sc; 9990b57cec5SDimitry Andric sc_list.GetContextAtIndex(0, sc); 10000b57cec5SDimitry Andric SourceInfo source_info; 10010b57cec5SDimitry Andric 10020b57cec5SDimitry Andric if (DisplayFunctionSource(sc, source_info, result)) { 10030b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 10040b57cec5SDimitry Andric } else { 10050b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 10060b57cec5SDimitry Andric } 10070b57cec5SDimitry Andric } 10080b57cec5SDimitry Andric return result.Succeeded(); 10090b57cec5SDimitry Andric } else if (m_options.address != LLDB_INVALID_ADDRESS) { 10100b57cec5SDimitry Andric Address so_addr; 10110b57cec5SDimitry Andric StreamString error_strm; 10120b57cec5SDimitry Andric SymbolContextList sc_list; 10130b57cec5SDimitry Andric 10140b57cec5SDimitry Andric if (target->GetSectionLoadList().IsEmpty()) { 10150b57cec5SDimitry Andric // The target isn't loaded yet, we need to lookup the file address in 10160b57cec5SDimitry Andric // all modules 10170b57cec5SDimitry Andric const ModuleList &module_list = target->GetImages(); 10180b57cec5SDimitry Andric const size_t num_modules = module_list.GetSize(); 10190b57cec5SDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 10200b57cec5SDimitry Andric ModuleSP module_sp(module_list.GetModuleAtIndex(i)); 10210b57cec5SDimitry Andric if (module_sp && 10220b57cec5SDimitry Andric module_sp->ResolveFileAddress(m_options.address, so_addr)) { 10230b57cec5SDimitry Andric SymbolContext sc; 10240b57cec5SDimitry Andric sc.Clear(true); 10250b57cec5SDimitry Andric if (module_sp->ResolveSymbolContextForAddress( 10260b57cec5SDimitry Andric so_addr, eSymbolContextEverything, sc) & 10270b57cec5SDimitry Andric eSymbolContextLineEntry) 10280b57cec5SDimitry Andric sc_list.Append(sc); 10290b57cec5SDimitry Andric } 10300b57cec5SDimitry Andric } 10310b57cec5SDimitry Andric 10320b57cec5SDimitry Andric if (sc_list.GetSize() == 0) { 10330b57cec5SDimitry Andric result.AppendErrorWithFormat( 10340b57cec5SDimitry Andric "no modules have source information for file address 0x%" PRIx64 10350b57cec5SDimitry Andric ".\n", 10360b57cec5SDimitry Andric m_options.address); 10370b57cec5SDimitry Andric return false; 10380b57cec5SDimitry Andric } 10390b57cec5SDimitry Andric } else { 10400b57cec5SDimitry Andric // The target has some things loaded, resolve this address to a compile 10410b57cec5SDimitry Andric // unit + file + line and display 10420b57cec5SDimitry Andric if (target->GetSectionLoadList().ResolveLoadAddress(m_options.address, 10430b57cec5SDimitry Andric so_addr)) { 10440b57cec5SDimitry Andric ModuleSP module_sp(so_addr.GetModule()); 10450b57cec5SDimitry Andric if (module_sp) { 10460b57cec5SDimitry Andric SymbolContext sc; 10470b57cec5SDimitry Andric sc.Clear(true); 10480b57cec5SDimitry Andric if (module_sp->ResolveSymbolContextForAddress( 10490b57cec5SDimitry Andric so_addr, eSymbolContextEverything, sc) & 10500b57cec5SDimitry Andric eSymbolContextLineEntry) { 10510b57cec5SDimitry Andric sc_list.Append(sc); 10520b57cec5SDimitry Andric } else { 10530b57cec5SDimitry Andric so_addr.Dump(&error_strm, nullptr, 10540b57cec5SDimitry Andric Address::DumpStyleModuleWithFileAddress); 10550b57cec5SDimitry Andric result.AppendErrorWithFormat("address resolves to %s, but there " 10560b57cec5SDimitry Andric "is no line table information " 10570b57cec5SDimitry Andric "available for this address.\n", 10580b57cec5SDimitry Andric error_strm.GetData()); 10590b57cec5SDimitry Andric return false; 10600b57cec5SDimitry Andric } 10610b57cec5SDimitry Andric } 10620b57cec5SDimitry Andric } 10630b57cec5SDimitry Andric 10640b57cec5SDimitry Andric if (sc_list.GetSize() == 0) { 10650b57cec5SDimitry Andric result.AppendErrorWithFormat( 10660b57cec5SDimitry Andric "no modules contain load address 0x%" PRIx64 ".\n", 10670b57cec5SDimitry Andric m_options.address); 10680b57cec5SDimitry Andric return false; 10690b57cec5SDimitry Andric } 10700b57cec5SDimitry Andric } 10710b57cec5SDimitry Andric uint32_t num_matches = sc_list.GetSize(); 10720b57cec5SDimitry Andric for (uint32_t i = 0; i < num_matches; ++i) { 10730b57cec5SDimitry Andric SymbolContext sc; 10740b57cec5SDimitry Andric sc_list.GetContextAtIndex(i, sc); 10750b57cec5SDimitry Andric if (sc.comp_unit) { 10760b57cec5SDimitry Andric if (m_options.show_bp_locs) { 10770b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 10780b57cec5SDimitry Andric const bool show_inlines = true; 1079480093f4SDimitry Andric m_breakpoint_locations.Reset(sc.comp_unit->GetPrimaryFile(), 0, 1080480093f4SDimitry Andric show_inlines); 10810b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 10820b57cec5SDimitry Andric target->shared_from_this()); 10830b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 10840b57cec5SDimitry Andric } 10850b57cec5SDimitry Andric 10860b57cec5SDimitry Andric bool show_fullpaths = true; 10870b57cec5SDimitry Andric bool show_module = true; 10880b57cec5SDimitry Andric bool show_inlined_frames = true; 10890b57cec5SDimitry Andric const bool show_function_arguments = true; 10900b57cec5SDimitry Andric const bool show_function_name = true; 10910b57cec5SDimitry Andric sc.DumpStopContext(&result.GetOutputStream(), 10920b57cec5SDimitry Andric m_exe_ctx.GetBestExecutionContextScope(), 10930b57cec5SDimitry Andric sc.line_entry.range.GetBaseAddress(), 10940b57cec5SDimitry Andric show_fullpaths, show_module, show_inlined_frames, 10950b57cec5SDimitry Andric show_function_arguments, show_function_name); 10960b57cec5SDimitry Andric result.GetOutputStream().EOL(); 10970b57cec5SDimitry Andric 10980b57cec5SDimitry Andric if (m_options.num_lines == 0) 10990b57cec5SDimitry Andric m_options.num_lines = 10; 11000b57cec5SDimitry Andric 11010b57cec5SDimitry Andric size_t lines_to_back_up = 11020b57cec5SDimitry Andric m_options.num_lines >= 10 ? 5 : m_options.num_lines / 2; 11030b57cec5SDimitry Andric 11040b57cec5SDimitry Andric const uint32_t column = 11050b57cec5SDimitry Andric (GetDebugger().GetStopShowColumn() != eStopShowColumnNone) 11060b57cec5SDimitry Andric ? sc.line_entry.column 11070b57cec5SDimitry Andric : 0; 11080b57cec5SDimitry Andric target->GetSourceManager().DisplaySourceLinesWithLineNumbers( 1109480093f4SDimitry Andric sc.comp_unit->GetPrimaryFile(), sc.line_entry.line, column, 1110480093f4SDimitry Andric lines_to_back_up, m_options.num_lines - lines_to_back_up, "->", 11110b57cec5SDimitry Andric &result.GetOutputStream(), GetBreakpointLocations()); 11120b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 11130b57cec5SDimitry Andric } 11140b57cec5SDimitry Andric } 11150b57cec5SDimitry Andric } else if (m_options.file_name.empty()) { 11160b57cec5SDimitry Andric // Last valid source manager context, or the current frame if no valid 11170b57cec5SDimitry Andric // last context in source manager. One little trick here, if you type the 11180b57cec5SDimitry Andric // exact same list command twice in a row, it is more likely because you 11190b57cec5SDimitry Andric // typed it once, then typed it again 11200b57cec5SDimitry Andric if (m_options.start_line == 0) { 11210b57cec5SDimitry Andric if (target->GetSourceManager().DisplayMoreWithLineNumbers( 11220b57cec5SDimitry Andric &result.GetOutputStream(), m_options.num_lines, 11230b57cec5SDimitry Andric m_options.reverse, GetBreakpointLocations())) { 11240b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 11250b57cec5SDimitry Andric } 11260b57cec5SDimitry Andric } else { 11270b57cec5SDimitry Andric if (m_options.num_lines == 0) 11280b57cec5SDimitry Andric m_options.num_lines = 10; 11290b57cec5SDimitry Andric 11300b57cec5SDimitry Andric if (m_options.show_bp_locs) { 11310b57cec5SDimitry Andric SourceManager::FileSP last_file_sp( 11320b57cec5SDimitry Andric target->GetSourceManager().GetLastFile()); 11330b57cec5SDimitry Andric if (last_file_sp) { 11340b57cec5SDimitry Andric const bool show_inlines = true; 11350b57cec5SDimitry Andric m_breakpoint_locations.Reset(last_file_sp->GetFileSpec(), 0, 11360b57cec5SDimitry Andric show_inlines); 11370b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 11380b57cec5SDimitry Andric target->shared_from_this()); 11390b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 11400b57cec5SDimitry Andric } 11410b57cec5SDimitry Andric } else 11420b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 11430b57cec5SDimitry Andric 11440b57cec5SDimitry Andric const uint32_t column = 0; 11450b57cec5SDimitry Andric if (target->GetSourceManager() 11460b57cec5SDimitry Andric .DisplaySourceLinesWithLineNumbersUsingLastFile( 11470b57cec5SDimitry Andric m_options.start_line, // Line to display 11480b57cec5SDimitry Andric m_options.num_lines, // Lines after line to 11490b57cec5SDimitry Andric UINT32_MAX, // Don't mark "line" 11500b57cec5SDimitry Andric column, 11510b57cec5SDimitry Andric "", // Don't mark "line" 11520b57cec5SDimitry Andric &result.GetOutputStream(), GetBreakpointLocations())) { 11530b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 11540b57cec5SDimitry Andric } 11550b57cec5SDimitry Andric } 11560b57cec5SDimitry Andric } else { 11570b57cec5SDimitry Andric const char *filename = m_options.file_name.c_str(); 11580b57cec5SDimitry Andric 11590b57cec5SDimitry Andric bool check_inlines = false; 11600b57cec5SDimitry Andric SymbolContextList sc_list; 11610b57cec5SDimitry Andric size_t num_matches = 0; 11620b57cec5SDimitry Andric 11630b57cec5SDimitry Andric if (!m_options.modules.empty()) { 11640b57cec5SDimitry Andric ModuleList matching_modules; 11650b57cec5SDimitry Andric for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) { 11660b57cec5SDimitry Andric FileSpec module_file_spec(m_options.modules[i]); 11670b57cec5SDimitry Andric if (module_file_spec) { 11680b57cec5SDimitry Andric ModuleSpec module_spec(module_file_spec); 11690b57cec5SDimitry Andric matching_modules.Clear(); 11700b57cec5SDimitry Andric target->GetImages().FindModules(module_spec, matching_modules); 11710b57cec5SDimitry Andric num_matches += matching_modules.ResolveSymbolContextForFilePath( 11720b57cec5SDimitry Andric filename, 0, check_inlines, 11730b57cec5SDimitry Andric SymbolContextItem(eSymbolContextModule | 11740b57cec5SDimitry Andric eSymbolContextCompUnit), 11750b57cec5SDimitry Andric sc_list); 11760b57cec5SDimitry Andric } 11770b57cec5SDimitry Andric } 11780b57cec5SDimitry Andric } else { 11790b57cec5SDimitry Andric num_matches = target->GetImages().ResolveSymbolContextForFilePath( 11800b57cec5SDimitry Andric filename, 0, check_inlines, 11810b57cec5SDimitry Andric eSymbolContextModule | eSymbolContextCompUnit, sc_list); 11820b57cec5SDimitry Andric } 11830b57cec5SDimitry Andric 11840b57cec5SDimitry Andric if (num_matches == 0) { 11850b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find source file \"%s\".\n", 11860b57cec5SDimitry Andric m_options.file_name.c_str()); 11870b57cec5SDimitry Andric return false; 11880b57cec5SDimitry Andric } 11890b57cec5SDimitry Andric 11900b57cec5SDimitry Andric if (num_matches > 1) { 11910b57cec5SDimitry Andric bool got_multiple = false; 1192480093f4SDimitry Andric CompileUnit *test_cu = nullptr; 11930b57cec5SDimitry Andric 11940b57cec5SDimitry Andric for (unsigned i = 0; i < num_matches; i++) { 11950b57cec5SDimitry Andric SymbolContext sc; 11960b57cec5SDimitry Andric sc_list.GetContextAtIndex(i, sc); 11970b57cec5SDimitry Andric if (sc.comp_unit) { 1198480093f4SDimitry Andric if (test_cu) { 1199480093f4SDimitry Andric if (test_cu != sc.comp_unit) 12000b57cec5SDimitry Andric got_multiple = true; 12010b57cec5SDimitry Andric break; 12020b57cec5SDimitry Andric } else 1203480093f4SDimitry Andric test_cu = sc.comp_unit; 12040b57cec5SDimitry Andric } 12050b57cec5SDimitry Andric } 12060b57cec5SDimitry Andric if (got_multiple) { 12070b57cec5SDimitry Andric result.AppendErrorWithFormat( 12080b57cec5SDimitry Andric "Multiple source files found matching: \"%s.\"\n", 12090b57cec5SDimitry Andric m_options.file_name.c_str()); 12100b57cec5SDimitry Andric return false; 12110b57cec5SDimitry Andric } 12120b57cec5SDimitry Andric } 12130b57cec5SDimitry Andric 12140b57cec5SDimitry Andric SymbolContext sc; 12150b57cec5SDimitry Andric if (sc_list.GetContextAtIndex(0, sc)) { 12160b57cec5SDimitry Andric if (sc.comp_unit) { 12170b57cec5SDimitry Andric if (m_options.show_bp_locs) { 12180b57cec5SDimitry Andric const bool show_inlines = true; 1219480093f4SDimitry Andric m_breakpoint_locations.Reset(sc.comp_unit->GetPrimaryFile(), 0, 1220480093f4SDimitry Andric show_inlines); 12210b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 12220b57cec5SDimitry Andric target->shared_from_this()); 12230b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 12240b57cec5SDimitry Andric } else 12250b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 12260b57cec5SDimitry Andric 12270b57cec5SDimitry Andric if (m_options.num_lines == 0) 12280b57cec5SDimitry Andric m_options.num_lines = 10; 12290b57cec5SDimitry Andric const uint32_t column = 0; 12300b57cec5SDimitry Andric target->GetSourceManager().DisplaySourceLinesWithLineNumbers( 1231480093f4SDimitry Andric sc.comp_unit->GetPrimaryFile(), m_options.start_line, column, 0, 1232480093f4SDimitry Andric m_options.num_lines, "", &result.GetOutputStream(), 1233480093f4SDimitry Andric GetBreakpointLocations()); 12340b57cec5SDimitry Andric 12350b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 12360b57cec5SDimitry Andric } else { 12370b57cec5SDimitry Andric result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n", 12380b57cec5SDimitry Andric m_options.file_name.c_str()); 12390b57cec5SDimitry Andric return false; 12400b57cec5SDimitry Andric } 12410b57cec5SDimitry Andric } 12420b57cec5SDimitry Andric } 12430b57cec5SDimitry Andric return result.Succeeded(); 12440b57cec5SDimitry Andric } 12450b57cec5SDimitry Andric 12460b57cec5SDimitry Andric const SymbolContextList *GetBreakpointLocations() { 12470b57cec5SDimitry Andric if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0) 12480b57cec5SDimitry Andric return &m_breakpoint_locations.GetFileLineMatches(); 12490b57cec5SDimitry Andric return nullptr; 12500b57cec5SDimitry Andric } 12510b57cec5SDimitry Andric 12520b57cec5SDimitry Andric CommandOptions m_options; 12530b57cec5SDimitry Andric FileLineResolver m_breakpoint_locations; 12540b57cec5SDimitry Andric std::string m_reverse_name; 12550b57cec5SDimitry Andric }; 12560b57cec5SDimitry Andric 12570b57cec5SDimitry Andric #pragma mark CommandObjectMultiwordSource 12580b57cec5SDimitry Andric // CommandObjectMultiwordSource 12590b57cec5SDimitry Andric 12600b57cec5SDimitry Andric CommandObjectMultiwordSource::CommandObjectMultiwordSource( 12610b57cec5SDimitry Andric CommandInterpreter &interpreter) 1262480093f4SDimitry Andric : CommandObjectMultiword(interpreter, "source", 1263480093f4SDimitry Andric "Commands for examining " 12640b57cec5SDimitry Andric "source code described by " 12650b57cec5SDimitry Andric "debug information for the " 12660b57cec5SDimitry Andric "current target process.", 12670b57cec5SDimitry Andric "source <subcommand> [<subcommand-options>]") { 12680b57cec5SDimitry Andric LoadSubCommand("info", 12690b57cec5SDimitry Andric CommandObjectSP(new CommandObjectSourceInfo(interpreter))); 12700b57cec5SDimitry Andric LoadSubCommand("list", 12710b57cec5SDimitry Andric CommandObjectSP(new CommandObjectSourceList(interpreter))); 12720b57cec5SDimitry Andric } 12730b57cec5SDimitry Andric 12740b57cec5SDimitry Andric CommandObjectMultiwordSource::~CommandObjectMultiwordSource() = default; 1275