15ffd83dbSDimitry Andric //===-- CommandObjectSource.cpp -------------------------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include "CommandObjectSource.h" 10*0b57cec5SDimitry Andric 11*0b57cec5SDimitry Andric #include "lldb/Core/Debugger.h" 12*0b57cec5SDimitry Andric #include "lldb/Core/FileLineResolver.h" 13*0b57cec5SDimitry Andric #include "lldb/Core/Module.h" 14*0b57cec5SDimitry Andric #include "lldb/Core/ModuleSpec.h" 15*0b57cec5SDimitry Andric #include "lldb/Core/SourceManager.h" 16*0b57cec5SDimitry Andric #include "lldb/Host/OptionParser.h" 17*0b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 18*0b57cec5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h" 19*0b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h" 20*0b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h" 21*0b57cec5SDimitry Andric #include "lldb/Symbol/Function.h" 22*0b57cec5SDimitry Andric #include "lldb/Symbol/Symbol.h" 23*0b57cec5SDimitry Andric #include "lldb/Target/SectionLoadList.h" 24*0b57cec5SDimitry Andric #include "lldb/Target/StackFrame.h" 25*0b57cec5SDimitry Andric #include "lldb/Utility/FileSpec.h" 26*0b57cec5SDimitry Andric 27*0b57cec5SDimitry Andric using namespace lldb; 28*0b57cec5SDimitry Andric using namespace lldb_private; 29*0b57cec5SDimitry Andric 30*0b57cec5SDimitry Andric #pragma mark CommandObjectSourceInfo 31*0b57cec5SDimitry Andric // CommandObjectSourceInfo - debug line entries dumping command 329dba64beSDimitry Andric #define LLDB_OPTIONS_source_info 339dba64beSDimitry Andric #include "CommandOptions.inc" 34*0b57cec5SDimitry Andric 35*0b57cec5SDimitry Andric class CommandObjectSourceInfo : public CommandObjectParsed { 36*0b57cec5SDimitry Andric class CommandOptions : public Options { 37*0b57cec5SDimitry Andric public: 38*0b57cec5SDimitry Andric CommandOptions() : Options() {} 39*0b57cec5SDimitry Andric 40*0b57cec5SDimitry Andric ~CommandOptions() override = default; 41*0b57cec5SDimitry Andric 42*0b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 43*0b57cec5SDimitry Andric ExecutionContext *execution_context) override { 44*0b57cec5SDimitry Andric Status error; 45*0b57cec5SDimitry Andric const int short_option = GetDefinitions()[option_idx].short_option; 46*0b57cec5SDimitry Andric switch (short_option) { 47*0b57cec5SDimitry Andric case 'l': 48*0b57cec5SDimitry Andric if (option_arg.getAsInteger(0, start_line)) 49*0b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line number: '%s'", 50*0b57cec5SDimitry Andric option_arg.str().c_str()); 51*0b57cec5SDimitry Andric break; 52*0b57cec5SDimitry Andric 53*0b57cec5SDimitry Andric case 'e': 54*0b57cec5SDimitry Andric if (option_arg.getAsInteger(0, end_line)) 55*0b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line number: '%s'", 56*0b57cec5SDimitry Andric option_arg.str().c_str()); 57*0b57cec5SDimitry Andric break; 58*0b57cec5SDimitry Andric 59*0b57cec5SDimitry Andric case 'c': 60*0b57cec5SDimitry Andric if (option_arg.getAsInteger(0, num_lines)) 61*0b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line count: '%s'", 62*0b57cec5SDimitry Andric option_arg.str().c_str()); 63*0b57cec5SDimitry Andric break; 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric case 'f': 665ffd83dbSDimitry Andric file_name = std::string(option_arg); 67*0b57cec5SDimitry Andric break; 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric case 'n': 705ffd83dbSDimitry Andric symbol_name = std::string(option_arg); 71*0b57cec5SDimitry Andric break; 72*0b57cec5SDimitry Andric 73*0b57cec5SDimitry Andric case 'a': { 74*0b57cec5SDimitry Andric address = OptionArgParser::ToAddress(execution_context, option_arg, 75*0b57cec5SDimitry Andric LLDB_INVALID_ADDRESS, &error); 76*0b57cec5SDimitry Andric } break; 77*0b57cec5SDimitry Andric case 's': 78*0b57cec5SDimitry Andric modules.push_back(std::string(option_arg)); 79*0b57cec5SDimitry Andric break; 80*0b57cec5SDimitry Andric default: 819dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 82*0b57cec5SDimitry Andric } 83*0b57cec5SDimitry Andric 84*0b57cec5SDimitry Andric return error; 85*0b57cec5SDimitry Andric } 86*0b57cec5SDimitry Andric 87*0b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 88*0b57cec5SDimitry Andric file_spec.Clear(); 89*0b57cec5SDimitry Andric file_name.clear(); 90*0b57cec5SDimitry Andric symbol_name.clear(); 91*0b57cec5SDimitry Andric address = LLDB_INVALID_ADDRESS; 92*0b57cec5SDimitry Andric start_line = 0; 93*0b57cec5SDimitry Andric end_line = 0; 94*0b57cec5SDimitry Andric num_lines = 0; 95*0b57cec5SDimitry Andric modules.clear(); 96*0b57cec5SDimitry Andric } 97*0b57cec5SDimitry Andric 98*0b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 99*0b57cec5SDimitry Andric return llvm::makeArrayRef(g_source_info_options); 100*0b57cec5SDimitry Andric } 101*0b57cec5SDimitry Andric 102*0b57cec5SDimitry Andric // Instance variables to hold the values for command options. 103*0b57cec5SDimitry Andric FileSpec file_spec; 104*0b57cec5SDimitry Andric std::string file_name; 105*0b57cec5SDimitry Andric std::string symbol_name; 106*0b57cec5SDimitry Andric lldb::addr_t address; 107*0b57cec5SDimitry Andric uint32_t start_line; 108*0b57cec5SDimitry Andric uint32_t end_line; 109*0b57cec5SDimitry Andric uint32_t num_lines; 110480093f4SDimitry Andric std::vector<std::string> modules; 111*0b57cec5SDimitry Andric }; 112*0b57cec5SDimitry Andric 113*0b57cec5SDimitry Andric public: 114*0b57cec5SDimitry Andric CommandObjectSourceInfo(CommandInterpreter &interpreter) 115*0b57cec5SDimitry Andric : CommandObjectParsed( 116*0b57cec5SDimitry Andric interpreter, "source info", 117*0b57cec5SDimitry Andric "Display source line information for the current target " 118*0b57cec5SDimitry Andric "process. Defaults to instruction pointer in current stack " 119*0b57cec5SDimitry Andric "frame.", 120*0b57cec5SDimitry Andric nullptr, eCommandRequiresTarget), 121*0b57cec5SDimitry Andric m_options() {} 122*0b57cec5SDimitry Andric 123*0b57cec5SDimitry Andric ~CommandObjectSourceInfo() override = default; 124*0b57cec5SDimitry Andric 125*0b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 126*0b57cec5SDimitry Andric 127*0b57cec5SDimitry Andric protected: 128*0b57cec5SDimitry Andric // Dump the line entries in each symbol context. Return the number of entries 129*0b57cec5SDimitry Andric // found. If module_list is set, only dump lines contained in one of the 130*0b57cec5SDimitry Andric // modules. If file_spec is set, only dump lines in the file. If the 131*0b57cec5SDimitry Andric // start_line option was specified, don't print lines less than start_line. 132*0b57cec5SDimitry Andric // If the end_line option was specified, don't print lines greater than 133*0b57cec5SDimitry Andric // end_line. If the num_lines option was specified, dont print more than 134*0b57cec5SDimitry Andric // num_lines entries. 135*0b57cec5SDimitry Andric uint32_t DumpLinesInSymbolContexts(Stream &strm, 136*0b57cec5SDimitry Andric const SymbolContextList &sc_list, 137*0b57cec5SDimitry Andric const ModuleList &module_list, 138*0b57cec5SDimitry Andric const FileSpec &file_spec) { 139*0b57cec5SDimitry Andric uint32_t start_line = m_options.start_line; 140*0b57cec5SDimitry Andric uint32_t end_line = m_options.end_line; 141*0b57cec5SDimitry Andric uint32_t num_lines = m_options.num_lines; 142*0b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 143*0b57cec5SDimitry Andric 144*0b57cec5SDimitry Andric uint32_t num_matches = 0; 145*0b57cec5SDimitry Andric // Dump all the line entries for the file in the list. 146*0b57cec5SDimitry Andric ConstString last_module_file_name; 147*0b57cec5SDimitry Andric uint32_t num_scs = sc_list.GetSize(); 148*0b57cec5SDimitry Andric for (uint32_t i = 0; i < num_scs; ++i) { 149*0b57cec5SDimitry Andric SymbolContext sc; 150*0b57cec5SDimitry Andric sc_list.GetContextAtIndex(i, sc); 151*0b57cec5SDimitry Andric if (sc.comp_unit) { 152*0b57cec5SDimitry Andric Module *module = sc.module_sp.get(); 153*0b57cec5SDimitry Andric CompileUnit *cu = sc.comp_unit; 154*0b57cec5SDimitry Andric const LineEntry &line_entry = sc.line_entry; 155*0b57cec5SDimitry Andric assert(module && cu); 156*0b57cec5SDimitry Andric 157*0b57cec5SDimitry Andric // Are we looking for specific modules, files or lines? 158*0b57cec5SDimitry Andric if (module_list.GetSize() && 159*0b57cec5SDimitry Andric module_list.GetIndexForModule(module) == LLDB_INVALID_INDEX32) 160*0b57cec5SDimitry Andric continue; 161480093f4SDimitry Andric if (!FileSpec::Match(file_spec, line_entry.file)) 162*0b57cec5SDimitry Andric continue; 163*0b57cec5SDimitry Andric if (start_line > 0 && line_entry.line < start_line) 164*0b57cec5SDimitry Andric continue; 165*0b57cec5SDimitry Andric if (end_line > 0 && line_entry.line > end_line) 166*0b57cec5SDimitry Andric continue; 167*0b57cec5SDimitry Andric if (num_lines > 0 && num_matches > num_lines) 168*0b57cec5SDimitry Andric continue; 169*0b57cec5SDimitry Andric 170*0b57cec5SDimitry Andric // Print a new header if the module changed. 171480093f4SDimitry Andric ConstString module_file_name = module->GetFileSpec().GetFilename(); 172*0b57cec5SDimitry Andric assert(module_file_name); 173*0b57cec5SDimitry Andric if (module_file_name != last_module_file_name) { 174*0b57cec5SDimitry Andric if (num_matches > 0) 175*0b57cec5SDimitry Andric strm << "\n\n"; 176*0b57cec5SDimitry Andric strm << "Lines found in module `" << module_file_name << "\n"; 177*0b57cec5SDimitry Andric } 178*0b57cec5SDimitry Andric // Dump the line entry. 179*0b57cec5SDimitry Andric line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu, 180*0b57cec5SDimitry Andric target, /*show_address_only=*/false); 181*0b57cec5SDimitry Andric strm << "\n"; 182*0b57cec5SDimitry Andric last_module_file_name = module_file_name; 183*0b57cec5SDimitry Andric num_matches++; 184*0b57cec5SDimitry Andric } 185*0b57cec5SDimitry Andric } 186*0b57cec5SDimitry Andric return num_matches; 187*0b57cec5SDimitry Andric } 188*0b57cec5SDimitry Andric 189*0b57cec5SDimitry Andric // Dump the requested line entries for the file in the compilation unit. 190*0b57cec5SDimitry Andric // Return the number of entries found. If module_list is set, only dump lines 191*0b57cec5SDimitry Andric // contained in one of the modules. If the start_line option was specified, 192*0b57cec5SDimitry Andric // don't print lines less than start_line. If the end_line option was 193*0b57cec5SDimitry Andric // specified, don't print lines greater than end_line. If the num_lines 194*0b57cec5SDimitry Andric // option was specified, dont print more than num_lines entries. 195*0b57cec5SDimitry Andric uint32_t DumpFileLinesInCompUnit(Stream &strm, Module *module, 196*0b57cec5SDimitry Andric CompileUnit *cu, const FileSpec &file_spec) { 197*0b57cec5SDimitry Andric uint32_t start_line = m_options.start_line; 198*0b57cec5SDimitry Andric uint32_t end_line = m_options.end_line; 199*0b57cec5SDimitry Andric uint32_t num_lines = m_options.num_lines; 200*0b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 201*0b57cec5SDimitry Andric 202*0b57cec5SDimitry Andric uint32_t num_matches = 0; 203*0b57cec5SDimitry Andric assert(module); 204*0b57cec5SDimitry Andric if (cu) { 205*0b57cec5SDimitry Andric assert(file_spec.GetFilename().AsCString()); 206*0b57cec5SDimitry Andric bool has_path = (file_spec.GetDirectory().AsCString() != nullptr); 207*0b57cec5SDimitry Andric const FileSpecList &cu_file_list = cu->GetSupportFiles(); 208*0b57cec5SDimitry Andric size_t file_idx = cu_file_list.FindFileIndex(0, file_spec, has_path); 209*0b57cec5SDimitry Andric if (file_idx != UINT32_MAX) { 210*0b57cec5SDimitry Andric // Update the file to how it appears in the CU. 211*0b57cec5SDimitry Andric const FileSpec &cu_file_spec = 212*0b57cec5SDimitry Andric cu_file_list.GetFileSpecAtIndex(file_idx); 213*0b57cec5SDimitry Andric 214*0b57cec5SDimitry Andric // Dump all matching lines at or above start_line for the file in the 215*0b57cec5SDimitry Andric // CU. 216*0b57cec5SDimitry Andric ConstString file_spec_name = file_spec.GetFilename(); 217480093f4SDimitry Andric ConstString module_file_name = module->GetFileSpec().GetFilename(); 218*0b57cec5SDimitry Andric bool cu_header_printed = false; 219*0b57cec5SDimitry Andric uint32_t line = start_line; 220*0b57cec5SDimitry Andric while (true) { 221*0b57cec5SDimitry Andric LineEntry line_entry; 222*0b57cec5SDimitry Andric 223*0b57cec5SDimitry Andric // Find the lowest index of a line entry with a line equal to or 224*0b57cec5SDimitry Andric // higher than 'line'. 225*0b57cec5SDimitry Andric uint32_t start_idx = 0; 226*0b57cec5SDimitry Andric start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec, 227*0b57cec5SDimitry Andric /*exact=*/false, &line_entry); 228*0b57cec5SDimitry Andric if (start_idx == UINT32_MAX) 229*0b57cec5SDimitry Andric // No more line entries for our file in this CU. 230*0b57cec5SDimitry Andric break; 231*0b57cec5SDimitry Andric 232*0b57cec5SDimitry Andric if (end_line > 0 && line_entry.line > end_line) 233*0b57cec5SDimitry Andric break; 234*0b57cec5SDimitry Andric 235*0b57cec5SDimitry Andric // Loop through to find any other entries for this line, dumping 236*0b57cec5SDimitry Andric // each. 237*0b57cec5SDimitry Andric line = line_entry.line; 238*0b57cec5SDimitry Andric do { 239*0b57cec5SDimitry Andric num_matches++; 240*0b57cec5SDimitry Andric if (num_lines > 0 && num_matches > num_lines) 241*0b57cec5SDimitry Andric break; 242480093f4SDimitry Andric assert(cu_file_spec == line_entry.file); 243*0b57cec5SDimitry Andric if (!cu_header_printed) { 244*0b57cec5SDimitry Andric if (num_matches > 0) 245*0b57cec5SDimitry Andric strm << "\n\n"; 246*0b57cec5SDimitry Andric strm << "Lines found for file " << file_spec_name 247480093f4SDimitry Andric << " in compilation unit " 248480093f4SDimitry Andric << cu->GetPrimaryFile().GetFilename() << " in `" 249*0b57cec5SDimitry Andric << module_file_name << "\n"; 250*0b57cec5SDimitry Andric cu_header_printed = true; 251*0b57cec5SDimitry Andric } 252*0b57cec5SDimitry Andric line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu, 253*0b57cec5SDimitry Andric target, /*show_address_only=*/false); 254*0b57cec5SDimitry Andric strm << "\n"; 255*0b57cec5SDimitry Andric 256*0b57cec5SDimitry Andric // Anymore after this one? 257*0b57cec5SDimitry Andric start_idx++; 258*0b57cec5SDimitry Andric start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec, 259*0b57cec5SDimitry Andric /*exact=*/true, &line_entry); 260*0b57cec5SDimitry Andric } while (start_idx != UINT32_MAX); 261*0b57cec5SDimitry Andric 262*0b57cec5SDimitry Andric // Try the next higher line, starting over at start_idx 0. 263*0b57cec5SDimitry Andric line++; 264*0b57cec5SDimitry Andric } 265*0b57cec5SDimitry Andric } 266*0b57cec5SDimitry Andric } 267*0b57cec5SDimitry Andric return num_matches; 268*0b57cec5SDimitry Andric } 269*0b57cec5SDimitry Andric 270*0b57cec5SDimitry Andric // Dump the requested line entries for the file in the module. Return the 271*0b57cec5SDimitry Andric // number of entries found. If module_list is set, only dump lines contained 272*0b57cec5SDimitry Andric // in one of the modules. If the start_line option was specified, don't print 273*0b57cec5SDimitry Andric // lines less than start_line. If the end_line option was specified, don't 274*0b57cec5SDimitry Andric // print lines greater than end_line. If the num_lines option was specified, 275*0b57cec5SDimitry Andric // dont print more than num_lines entries. 276*0b57cec5SDimitry Andric uint32_t DumpFileLinesInModule(Stream &strm, Module *module, 277*0b57cec5SDimitry Andric const FileSpec &file_spec) { 278*0b57cec5SDimitry Andric uint32_t num_matches = 0; 279*0b57cec5SDimitry Andric if (module) { 280*0b57cec5SDimitry Andric // Look through all the compilation units (CUs) in this module for ones 281*0b57cec5SDimitry Andric // that contain lines of code from this source file. 282*0b57cec5SDimitry Andric for (size_t i = 0; i < module->GetNumCompileUnits(); i++) { 283*0b57cec5SDimitry Andric // Look for a matching source file in this CU. 284*0b57cec5SDimitry Andric CompUnitSP cu_sp(module->GetCompileUnitAtIndex(i)); 285*0b57cec5SDimitry Andric if (cu_sp) { 286*0b57cec5SDimitry Andric num_matches += 287*0b57cec5SDimitry Andric DumpFileLinesInCompUnit(strm, module, cu_sp.get(), file_spec); 288*0b57cec5SDimitry Andric } 289*0b57cec5SDimitry Andric } 290*0b57cec5SDimitry Andric } 291*0b57cec5SDimitry Andric return num_matches; 292*0b57cec5SDimitry Andric } 293*0b57cec5SDimitry Andric 294*0b57cec5SDimitry Andric // Given an address and a list of modules, append the symbol contexts of all 295*0b57cec5SDimitry Andric // line entries containing the address found in the modules and return the 296*0b57cec5SDimitry Andric // count of matches. If none is found, return an error in 'error_strm'. 297*0b57cec5SDimitry Andric size_t GetSymbolContextsForAddress(const ModuleList &module_list, 298*0b57cec5SDimitry Andric lldb::addr_t addr, 299*0b57cec5SDimitry Andric SymbolContextList &sc_list, 300*0b57cec5SDimitry Andric StreamString &error_strm) { 301*0b57cec5SDimitry Andric Address so_addr; 302*0b57cec5SDimitry Andric size_t num_matches = 0; 303*0b57cec5SDimitry Andric assert(module_list.GetSize() > 0); 304*0b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 305*0b57cec5SDimitry Andric if (target->GetSectionLoadList().IsEmpty()) { 306*0b57cec5SDimitry Andric // The target isn't loaded yet, we need to lookup the file address in all 307*0b57cec5SDimitry Andric // modules. Note: the module list option does not apply to addresses. 308*0b57cec5SDimitry Andric const size_t num_modules = module_list.GetSize(); 309*0b57cec5SDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 310*0b57cec5SDimitry Andric ModuleSP module_sp(module_list.GetModuleAtIndex(i)); 311*0b57cec5SDimitry Andric if (!module_sp) 312*0b57cec5SDimitry Andric continue; 313*0b57cec5SDimitry Andric if (module_sp->ResolveFileAddress(addr, so_addr)) { 314*0b57cec5SDimitry Andric SymbolContext sc; 315*0b57cec5SDimitry Andric sc.Clear(true); 316*0b57cec5SDimitry Andric if (module_sp->ResolveSymbolContextForAddress( 317*0b57cec5SDimitry Andric so_addr, eSymbolContextEverything, sc) & 318*0b57cec5SDimitry Andric eSymbolContextLineEntry) { 319*0b57cec5SDimitry Andric sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false); 320*0b57cec5SDimitry Andric ++num_matches; 321*0b57cec5SDimitry Andric } 322*0b57cec5SDimitry Andric } 323*0b57cec5SDimitry Andric } 324*0b57cec5SDimitry Andric if (num_matches == 0) 325*0b57cec5SDimitry Andric error_strm.Printf("Source information for file address 0x%" PRIx64 326*0b57cec5SDimitry Andric " not found in any modules.\n", 327*0b57cec5SDimitry Andric addr); 328*0b57cec5SDimitry Andric } else { 329*0b57cec5SDimitry Andric // The target has some things loaded, resolve this address to a compile 330*0b57cec5SDimitry Andric // unit + file + line and display 331*0b57cec5SDimitry Andric if (target->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) { 332*0b57cec5SDimitry Andric ModuleSP module_sp(so_addr.GetModule()); 333*0b57cec5SDimitry Andric // Check to make sure this module is in our list. 334480093f4SDimitry Andric if (module_sp && module_list.GetIndexForModule(module_sp.get()) != 335*0b57cec5SDimitry Andric LLDB_INVALID_INDEX32) { 336*0b57cec5SDimitry Andric SymbolContext sc; 337*0b57cec5SDimitry Andric sc.Clear(true); 338*0b57cec5SDimitry Andric if (module_sp->ResolveSymbolContextForAddress( 339*0b57cec5SDimitry Andric so_addr, eSymbolContextEverything, sc) & 340*0b57cec5SDimitry Andric eSymbolContextLineEntry) { 341*0b57cec5SDimitry Andric sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false); 342*0b57cec5SDimitry Andric ++num_matches; 343*0b57cec5SDimitry Andric } else { 344*0b57cec5SDimitry Andric StreamString addr_strm; 345*0b57cec5SDimitry Andric so_addr.Dump(&addr_strm, nullptr, 346*0b57cec5SDimitry Andric Address::DumpStyleModuleWithFileAddress); 347*0b57cec5SDimitry Andric error_strm.Printf( 348*0b57cec5SDimitry Andric "Address 0x%" PRIx64 " resolves to %s, but there is" 349*0b57cec5SDimitry Andric " no source information available for this address.\n", 350*0b57cec5SDimitry Andric addr, addr_strm.GetData()); 351*0b57cec5SDimitry Andric } 352*0b57cec5SDimitry Andric } else { 353*0b57cec5SDimitry Andric StreamString addr_strm; 354*0b57cec5SDimitry Andric so_addr.Dump(&addr_strm, nullptr, 355*0b57cec5SDimitry Andric Address::DumpStyleModuleWithFileAddress); 356*0b57cec5SDimitry Andric error_strm.Printf("Address 0x%" PRIx64 357*0b57cec5SDimitry Andric " resolves to %s, but it cannot" 358*0b57cec5SDimitry Andric " be found in any modules.\n", 359*0b57cec5SDimitry Andric addr, addr_strm.GetData()); 360*0b57cec5SDimitry Andric } 361*0b57cec5SDimitry Andric } else 362*0b57cec5SDimitry Andric error_strm.Printf("Unable to resolve address 0x%" PRIx64 ".\n", addr); 363*0b57cec5SDimitry Andric } 364*0b57cec5SDimitry Andric return num_matches; 365*0b57cec5SDimitry Andric } 366*0b57cec5SDimitry Andric 367*0b57cec5SDimitry Andric // Dump the line entries found in functions matching the name specified in 368*0b57cec5SDimitry Andric // the option. 369*0b57cec5SDimitry Andric bool DumpLinesInFunctions(CommandReturnObject &result) { 370*0b57cec5SDimitry Andric SymbolContextList sc_list_funcs; 371*0b57cec5SDimitry Andric ConstString name(m_options.symbol_name.c_str()); 372*0b57cec5SDimitry Andric SymbolContextList sc_list_lines; 373*0b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 374*0b57cec5SDimitry Andric uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); 375*0b57cec5SDimitry Andric 376*0b57cec5SDimitry Andric // Note: module_list can't be const& because FindFunctionSymbols isn't 377*0b57cec5SDimitry Andric // const. 378*0b57cec5SDimitry Andric ModuleList module_list = 379*0b57cec5SDimitry Andric (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages(); 380*0b57cec5SDimitry Andric module_list.FindFunctions(name, eFunctionNameTypeAuto, 381*0b57cec5SDimitry Andric /*include_symbols=*/false, 3829dba64beSDimitry Andric /*include_inlines=*/true, sc_list_funcs); 3839dba64beSDimitry Andric size_t num_matches = sc_list_funcs.GetSize(); 3849dba64beSDimitry Andric 385*0b57cec5SDimitry Andric if (!num_matches) { 386*0b57cec5SDimitry Andric // If we didn't find any functions with that name, try searching for 387*0b57cec5SDimitry Andric // symbols that line up exactly with function addresses. 388*0b57cec5SDimitry Andric SymbolContextList sc_list_symbols; 389480093f4SDimitry Andric module_list.FindFunctionSymbols(name, eFunctionNameTypeAuto, 390480093f4SDimitry Andric sc_list_symbols); 3919dba64beSDimitry Andric size_t num_symbol_matches = sc_list_symbols.GetSize(); 392*0b57cec5SDimitry Andric for (size_t i = 0; i < num_symbol_matches; i++) { 393*0b57cec5SDimitry Andric SymbolContext sc; 394*0b57cec5SDimitry Andric sc_list_symbols.GetContextAtIndex(i, sc); 395*0b57cec5SDimitry Andric if (sc.symbol && sc.symbol->ValueIsAddress()) { 396*0b57cec5SDimitry Andric const Address &base_address = sc.symbol->GetAddressRef(); 397*0b57cec5SDimitry Andric Function *function = base_address.CalculateSymbolContextFunction(); 398*0b57cec5SDimitry Andric if (function) { 399*0b57cec5SDimitry Andric sc_list_funcs.Append(SymbolContext(function)); 400*0b57cec5SDimitry Andric num_matches++; 401*0b57cec5SDimitry Andric } 402*0b57cec5SDimitry Andric } 403*0b57cec5SDimitry Andric } 404*0b57cec5SDimitry Andric } 405*0b57cec5SDimitry Andric if (num_matches == 0) { 406*0b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find function named \'%s\'.\n", 407*0b57cec5SDimitry Andric m_options.symbol_name.c_str()); 408*0b57cec5SDimitry Andric return false; 409*0b57cec5SDimitry Andric } 410*0b57cec5SDimitry Andric for (size_t i = 0; i < num_matches; i++) { 411*0b57cec5SDimitry Andric SymbolContext sc; 412*0b57cec5SDimitry Andric sc_list_funcs.GetContextAtIndex(i, sc); 413*0b57cec5SDimitry Andric bool context_found_for_symbol = false; 414*0b57cec5SDimitry Andric // Loop through all the ranges in the function. 415*0b57cec5SDimitry Andric AddressRange range; 416*0b57cec5SDimitry Andric for (uint32_t r = 0; 417*0b57cec5SDimitry Andric sc.GetAddressRange(eSymbolContextEverything, r, 418*0b57cec5SDimitry Andric /*use_inline_block_range=*/true, range); 419*0b57cec5SDimitry Andric ++r) { 420*0b57cec5SDimitry Andric // Append the symbol contexts for each address in the range to 421*0b57cec5SDimitry Andric // sc_list_lines. 422*0b57cec5SDimitry Andric const Address &base_address = range.GetBaseAddress(); 423*0b57cec5SDimitry Andric const addr_t size = range.GetByteSize(); 424*0b57cec5SDimitry Andric lldb::addr_t start_addr = base_address.GetLoadAddress(target); 425*0b57cec5SDimitry Andric if (start_addr == LLDB_INVALID_ADDRESS) 426*0b57cec5SDimitry Andric start_addr = base_address.GetFileAddress(); 427*0b57cec5SDimitry Andric lldb::addr_t end_addr = start_addr + size; 428*0b57cec5SDimitry Andric for (lldb::addr_t addr = start_addr; addr < end_addr; 429*0b57cec5SDimitry Andric addr += addr_byte_size) { 430*0b57cec5SDimitry Andric StreamString error_strm; 431*0b57cec5SDimitry Andric if (!GetSymbolContextsForAddress(module_list, addr, sc_list_lines, 432*0b57cec5SDimitry Andric error_strm)) 433*0b57cec5SDimitry Andric result.AppendWarningWithFormat("in symbol '%s': %s", 434*0b57cec5SDimitry Andric sc.GetFunctionName().AsCString(), 435*0b57cec5SDimitry Andric error_strm.GetData()); 436*0b57cec5SDimitry Andric else 437*0b57cec5SDimitry Andric context_found_for_symbol = true; 438*0b57cec5SDimitry Andric } 439*0b57cec5SDimitry Andric } 440*0b57cec5SDimitry Andric if (!context_found_for_symbol) 441*0b57cec5SDimitry Andric result.AppendWarningWithFormat("Unable to find line information" 442*0b57cec5SDimitry Andric " for matching symbol '%s'.\n", 443*0b57cec5SDimitry Andric sc.GetFunctionName().AsCString()); 444*0b57cec5SDimitry Andric } 445*0b57cec5SDimitry Andric if (sc_list_lines.GetSize() == 0) { 446*0b57cec5SDimitry Andric result.AppendErrorWithFormat("No line information could be found" 447*0b57cec5SDimitry Andric " for any symbols matching '%s'.\n", 448*0b57cec5SDimitry Andric name.AsCString()); 449*0b57cec5SDimitry Andric return false; 450*0b57cec5SDimitry Andric } 451*0b57cec5SDimitry Andric FileSpec file_spec; 452*0b57cec5SDimitry Andric if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list_lines, 453*0b57cec5SDimitry Andric module_list, file_spec)) { 454*0b57cec5SDimitry Andric result.AppendErrorWithFormat( 455*0b57cec5SDimitry Andric "Unable to dump line information for symbol '%s'.\n", 456*0b57cec5SDimitry Andric name.AsCString()); 457*0b57cec5SDimitry Andric return false; 458*0b57cec5SDimitry Andric } 459*0b57cec5SDimitry Andric return true; 460*0b57cec5SDimitry Andric } 461*0b57cec5SDimitry Andric 462*0b57cec5SDimitry Andric // Dump the line entries found for the address specified in the option. 463*0b57cec5SDimitry Andric bool DumpLinesForAddress(CommandReturnObject &result) { 464*0b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 465*0b57cec5SDimitry Andric SymbolContextList sc_list; 466*0b57cec5SDimitry Andric 467*0b57cec5SDimitry Andric StreamString error_strm; 468*0b57cec5SDimitry Andric if (!GetSymbolContextsForAddress(target->GetImages(), m_options.address, 469*0b57cec5SDimitry Andric sc_list, error_strm)) { 470*0b57cec5SDimitry Andric result.AppendErrorWithFormat("%s.\n", error_strm.GetData()); 471*0b57cec5SDimitry Andric return false; 472*0b57cec5SDimitry Andric } 473*0b57cec5SDimitry Andric ModuleList module_list; 474*0b57cec5SDimitry Andric FileSpec file_spec; 475*0b57cec5SDimitry Andric if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list, 476*0b57cec5SDimitry Andric module_list, file_spec)) { 477*0b57cec5SDimitry Andric result.AppendErrorWithFormat("No modules contain load address 0x%" PRIx64 478*0b57cec5SDimitry Andric ".\n", 479*0b57cec5SDimitry Andric m_options.address); 480*0b57cec5SDimitry Andric return false; 481*0b57cec5SDimitry Andric } 482*0b57cec5SDimitry Andric return true; 483*0b57cec5SDimitry Andric } 484*0b57cec5SDimitry Andric 485*0b57cec5SDimitry Andric // Dump the line entries found in the file specified in the option. 486*0b57cec5SDimitry Andric bool DumpLinesForFile(CommandReturnObject &result) { 487*0b57cec5SDimitry Andric FileSpec file_spec(m_options.file_name); 488*0b57cec5SDimitry Andric const char *filename = m_options.file_name.c_str(); 489*0b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 490*0b57cec5SDimitry Andric const ModuleList &module_list = 491*0b57cec5SDimitry Andric (m_module_list.GetSize() > 0) ? m_module_list : target->GetImages(); 492*0b57cec5SDimitry Andric 493*0b57cec5SDimitry Andric bool displayed_something = false; 494*0b57cec5SDimitry Andric const size_t num_modules = module_list.GetSize(); 495*0b57cec5SDimitry Andric for (uint32_t i = 0; i < num_modules; ++i) { 496*0b57cec5SDimitry Andric // Dump lines for this module. 497*0b57cec5SDimitry Andric Module *module = module_list.GetModulePointerAtIndex(i); 498*0b57cec5SDimitry Andric assert(module); 499*0b57cec5SDimitry Andric if (DumpFileLinesInModule(result.GetOutputStream(), module, file_spec)) 500*0b57cec5SDimitry Andric displayed_something = true; 501*0b57cec5SDimitry Andric } 502*0b57cec5SDimitry Andric if (!displayed_something) { 503*0b57cec5SDimitry Andric result.AppendErrorWithFormat("No source filenames matched '%s'.\n", 504*0b57cec5SDimitry Andric filename); 505*0b57cec5SDimitry Andric return false; 506*0b57cec5SDimitry Andric } 507*0b57cec5SDimitry Andric return true; 508*0b57cec5SDimitry Andric } 509*0b57cec5SDimitry Andric 510*0b57cec5SDimitry Andric // Dump the line entries for the current frame. 511*0b57cec5SDimitry Andric bool DumpLinesForFrame(CommandReturnObject &result) { 512*0b57cec5SDimitry Andric StackFrame *cur_frame = m_exe_ctx.GetFramePtr(); 513*0b57cec5SDimitry Andric if (cur_frame == nullptr) { 514*0b57cec5SDimitry Andric result.AppendError( 515*0b57cec5SDimitry Andric "No selected frame to use to find the default source."); 516*0b57cec5SDimitry Andric return false; 517*0b57cec5SDimitry Andric } else if (!cur_frame->HasDebugInformation()) { 518*0b57cec5SDimitry Andric result.AppendError("No debug info for the selected frame."); 519*0b57cec5SDimitry Andric return false; 520*0b57cec5SDimitry Andric } else { 521*0b57cec5SDimitry Andric const SymbolContext &sc = 522*0b57cec5SDimitry Andric cur_frame->GetSymbolContext(eSymbolContextLineEntry); 523*0b57cec5SDimitry Andric SymbolContextList sc_list; 524*0b57cec5SDimitry Andric sc_list.Append(sc); 525*0b57cec5SDimitry Andric ModuleList module_list; 526*0b57cec5SDimitry Andric FileSpec file_spec; 527*0b57cec5SDimitry Andric if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list, 528*0b57cec5SDimitry Andric module_list, file_spec)) { 529*0b57cec5SDimitry Andric result.AppendError( 530*0b57cec5SDimitry Andric "No source line info available for the selected frame."); 531*0b57cec5SDimitry Andric return false; 532*0b57cec5SDimitry Andric } 533*0b57cec5SDimitry Andric } 534*0b57cec5SDimitry Andric return true; 535*0b57cec5SDimitry Andric } 536*0b57cec5SDimitry Andric 537*0b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 538*0b57cec5SDimitry Andric const size_t argc = command.GetArgumentCount(); 539*0b57cec5SDimitry Andric 540*0b57cec5SDimitry Andric if (argc != 0) { 541*0b57cec5SDimitry Andric result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", 542*0b57cec5SDimitry Andric GetCommandName().str().c_str()); 543*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 544*0b57cec5SDimitry Andric return false; 545*0b57cec5SDimitry Andric } 546*0b57cec5SDimitry Andric 547*0b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 548*0b57cec5SDimitry Andric if (target == nullptr) { 549*0b57cec5SDimitry Andric target = GetDebugger().GetSelectedTarget().get(); 550*0b57cec5SDimitry Andric if (target == nullptr) { 551*0b57cec5SDimitry Andric result.AppendError("invalid target, create a debug target using the " 552*0b57cec5SDimitry Andric "'target create' command."); 553*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 554*0b57cec5SDimitry Andric return false; 555*0b57cec5SDimitry Andric } 556*0b57cec5SDimitry Andric } 557*0b57cec5SDimitry Andric 558*0b57cec5SDimitry Andric uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); 559*0b57cec5SDimitry Andric result.GetOutputStream().SetAddressByteSize(addr_byte_size); 560*0b57cec5SDimitry Andric result.GetErrorStream().SetAddressByteSize(addr_byte_size); 561*0b57cec5SDimitry Andric 562*0b57cec5SDimitry Andric // Collect the list of modules to search. 563*0b57cec5SDimitry Andric m_module_list.Clear(); 564*0b57cec5SDimitry Andric if (!m_options.modules.empty()) { 565*0b57cec5SDimitry Andric for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) { 566*0b57cec5SDimitry Andric FileSpec module_file_spec(m_options.modules[i]); 567*0b57cec5SDimitry Andric if (module_file_spec) { 568*0b57cec5SDimitry Andric ModuleSpec module_spec(module_file_spec); 5699dba64beSDimitry Andric target->GetImages().FindModules(module_spec, m_module_list); 5709dba64beSDimitry Andric if (m_module_list.IsEmpty()) 571*0b57cec5SDimitry Andric result.AppendWarningWithFormat("No module found for '%s'.\n", 572*0b57cec5SDimitry Andric m_options.modules[i].c_str()); 573*0b57cec5SDimitry Andric } 574*0b57cec5SDimitry Andric } 575*0b57cec5SDimitry Andric if (!m_module_list.GetSize()) { 576*0b57cec5SDimitry Andric result.AppendError("No modules match the input."); 577*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 578*0b57cec5SDimitry Andric return false; 579*0b57cec5SDimitry Andric } 580*0b57cec5SDimitry Andric } else if (target->GetImages().GetSize() == 0) { 581*0b57cec5SDimitry Andric result.AppendError("The target has no associated executable images."); 582*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 583*0b57cec5SDimitry Andric return false; 584*0b57cec5SDimitry Andric } 585*0b57cec5SDimitry Andric 586*0b57cec5SDimitry Andric // Check the arguments to see what lines we should dump. 587*0b57cec5SDimitry Andric if (!m_options.symbol_name.empty()) { 588*0b57cec5SDimitry Andric // Print lines for symbol. 589*0b57cec5SDimitry Andric if (DumpLinesInFunctions(result)) 590*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 591*0b57cec5SDimitry Andric else 592*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 593*0b57cec5SDimitry Andric } else if (m_options.address != LLDB_INVALID_ADDRESS) { 594*0b57cec5SDimitry Andric // Print lines for an address. 595*0b57cec5SDimitry Andric if (DumpLinesForAddress(result)) 596*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 597*0b57cec5SDimitry Andric else 598*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 599*0b57cec5SDimitry Andric } else if (!m_options.file_name.empty()) { 600*0b57cec5SDimitry Andric // Dump lines for a file. 601*0b57cec5SDimitry Andric if (DumpLinesForFile(result)) 602*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 603*0b57cec5SDimitry Andric else 604*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 605*0b57cec5SDimitry Andric } else { 606*0b57cec5SDimitry Andric // Dump the line for the current frame. 607*0b57cec5SDimitry Andric if (DumpLinesForFrame(result)) 608*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 609*0b57cec5SDimitry Andric else 610*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 611*0b57cec5SDimitry Andric } 612*0b57cec5SDimitry Andric return result.Succeeded(); 613*0b57cec5SDimitry Andric } 614*0b57cec5SDimitry Andric 615*0b57cec5SDimitry Andric CommandOptions m_options; 616*0b57cec5SDimitry Andric ModuleList m_module_list; 617*0b57cec5SDimitry Andric }; 618*0b57cec5SDimitry Andric 619*0b57cec5SDimitry Andric #pragma mark CommandObjectSourceList 620*0b57cec5SDimitry Andric // CommandObjectSourceList 6219dba64beSDimitry Andric #define LLDB_OPTIONS_source_list 6229dba64beSDimitry Andric #include "CommandOptions.inc" 623*0b57cec5SDimitry Andric 624*0b57cec5SDimitry Andric class CommandObjectSourceList : public CommandObjectParsed { 625*0b57cec5SDimitry Andric class CommandOptions : public Options { 626*0b57cec5SDimitry Andric public: 627*0b57cec5SDimitry Andric CommandOptions() : Options() {} 628*0b57cec5SDimitry Andric 629*0b57cec5SDimitry Andric ~CommandOptions() override = default; 630*0b57cec5SDimitry Andric 631*0b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 632*0b57cec5SDimitry Andric ExecutionContext *execution_context) override { 633*0b57cec5SDimitry Andric Status error; 634*0b57cec5SDimitry Andric const int short_option = GetDefinitions()[option_idx].short_option; 635*0b57cec5SDimitry Andric switch (short_option) { 636*0b57cec5SDimitry Andric case 'l': 637*0b57cec5SDimitry Andric if (option_arg.getAsInteger(0, start_line)) 638*0b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line number: '%s'", 639*0b57cec5SDimitry Andric option_arg.str().c_str()); 640*0b57cec5SDimitry Andric break; 641*0b57cec5SDimitry Andric 642*0b57cec5SDimitry Andric case 'c': 643*0b57cec5SDimitry Andric if (option_arg.getAsInteger(0, num_lines)) 644*0b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid line count: '%s'", 645*0b57cec5SDimitry Andric option_arg.str().c_str()); 646*0b57cec5SDimitry Andric break; 647*0b57cec5SDimitry Andric 648*0b57cec5SDimitry Andric case 'f': 6495ffd83dbSDimitry Andric file_name = std::string(option_arg); 650*0b57cec5SDimitry Andric break; 651*0b57cec5SDimitry Andric 652*0b57cec5SDimitry Andric case 'n': 6535ffd83dbSDimitry Andric symbol_name = std::string(option_arg); 654*0b57cec5SDimitry Andric break; 655*0b57cec5SDimitry Andric 656*0b57cec5SDimitry Andric case 'a': { 657*0b57cec5SDimitry Andric address = OptionArgParser::ToAddress(execution_context, option_arg, 658*0b57cec5SDimitry Andric LLDB_INVALID_ADDRESS, &error); 659*0b57cec5SDimitry Andric } break; 660*0b57cec5SDimitry Andric case 's': 661*0b57cec5SDimitry Andric modules.push_back(std::string(option_arg)); 662*0b57cec5SDimitry Andric break; 663*0b57cec5SDimitry Andric 664*0b57cec5SDimitry Andric case 'b': 665*0b57cec5SDimitry Andric show_bp_locs = true; 666*0b57cec5SDimitry Andric break; 667*0b57cec5SDimitry Andric case 'r': 668*0b57cec5SDimitry Andric reverse = true; 669*0b57cec5SDimitry Andric break; 670*0b57cec5SDimitry Andric default: 6719dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 672*0b57cec5SDimitry Andric } 673*0b57cec5SDimitry Andric 674*0b57cec5SDimitry Andric return error; 675*0b57cec5SDimitry Andric } 676*0b57cec5SDimitry Andric 677*0b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 678*0b57cec5SDimitry Andric file_spec.Clear(); 679*0b57cec5SDimitry Andric file_name.clear(); 680*0b57cec5SDimitry Andric symbol_name.clear(); 681*0b57cec5SDimitry Andric address = LLDB_INVALID_ADDRESS; 682*0b57cec5SDimitry Andric start_line = 0; 683*0b57cec5SDimitry Andric num_lines = 0; 684*0b57cec5SDimitry Andric show_bp_locs = false; 685*0b57cec5SDimitry Andric reverse = false; 686*0b57cec5SDimitry Andric modules.clear(); 687*0b57cec5SDimitry Andric } 688*0b57cec5SDimitry Andric 689*0b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 690*0b57cec5SDimitry Andric return llvm::makeArrayRef(g_source_list_options); 691*0b57cec5SDimitry Andric } 692*0b57cec5SDimitry Andric 693*0b57cec5SDimitry Andric // Instance variables to hold the values for command options. 694*0b57cec5SDimitry Andric FileSpec file_spec; 695*0b57cec5SDimitry Andric std::string file_name; 696*0b57cec5SDimitry Andric std::string symbol_name; 697*0b57cec5SDimitry Andric lldb::addr_t address; 698*0b57cec5SDimitry Andric uint32_t start_line; 699*0b57cec5SDimitry Andric uint32_t num_lines; 700480093f4SDimitry Andric std::vector<std::string> modules; 701*0b57cec5SDimitry Andric bool show_bp_locs; 702*0b57cec5SDimitry Andric bool reverse; 703*0b57cec5SDimitry Andric }; 704*0b57cec5SDimitry Andric 705*0b57cec5SDimitry Andric public: 706*0b57cec5SDimitry Andric CommandObjectSourceList(CommandInterpreter &interpreter) 707*0b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "source list", 708*0b57cec5SDimitry Andric "Display source code for the current target " 709*0b57cec5SDimitry Andric "process as specified by options.", 710*0b57cec5SDimitry Andric nullptr, eCommandRequiresTarget), 711*0b57cec5SDimitry Andric m_options() {} 712*0b57cec5SDimitry Andric 713*0b57cec5SDimitry Andric ~CommandObjectSourceList() override = default; 714*0b57cec5SDimitry Andric 715*0b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 716*0b57cec5SDimitry Andric 717*0b57cec5SDimitry Andric const char *GetRepeatCommand(Args ¤t_command_args, 718*0b57cec5SDimitry Andric uint32_t index) override { 719*0b57cec5SDimitry Andric // This is kind of gross, but the command hasn't been parsed yet so we 720*0b57cec5SDimitry Andric // can't look at the option values for this invocation... I have to scan 721*0b57cec5SDimitry Andric // the arguments directly. 722*0b57cec5SDimitry Andric auto iter = 723*0b57cec5SDimitry Andric llvm::find_if(current_command_args, [](const Args::ArgEntry &e) { 7249dba64beSDimitry Andric return e.ref() == "-r" || e.ref() == "--reverse"; 725*0b57cec5SDimitry Andric }); 726*0b57cec5SDimitry Andric if (iter == current_command_args.end()) 727*0b57cec5SDimitry Andric return m_cmd_name.c_str(); 728*0b57cec5SDimitry Andric 729*0b57cec5SDimitry Andric if (m_reverse_name.empty()) { 730*0b57cec5SDimitry Andric m_reverse_name = m_cmd_name; 731*0b57cec5SDimitry Andric m_reverse_name.append(" -r"); 732*0b57cec5SDimitry Andric } 733*0b57cec5SDimitry Andric return m_reverse_name.c_str(); 734*0b57cec5SDimitry Andric } 735*0b57cec5SDimitry Andric 736*0b57cec5SDimitry Andric protected: 737*0b57cec5SDimitry Andric struct SourceInfo { 738*0b57cec5SDimitry Andric ConstString function; 739*0b57cec5SDimitry Andric LineEntry line_entry; 740*0b57cec5SDimitry Andric 741*0b57cec5SDimitry Andric SourceInfo(ConstString name, const LineEntry &line_entry) 742*0b57cec5SDimitry Andric : function(name), line_entry(line_entry) {} 743*0b57cec5SDimitry Andric 744*0b57cec5SDimitry Andric SourceInfo() : function(), line_entry() {} 745*0b57cec5SDimitry Andric 746*0b57cec5SDimitry Andric bool IsValid() const { return (bool)function && line_entry.IsValid(); } 747*0b57cec5SDimitry Andric 748*0b57cec5SDimitry Andric bool operator==(const SourceInfo &rhs) const { 749*0b57cec5SDimitry Andric return function == rhs.function && 750*0b57cec5SDimitry Andric line_entry.original_file == rhs.line_entry.original_file && 751*0b57cec5SDimitry Andric line_entry.line == rhs.line_entry.line; 752*0b57cec5SDimitry Andric } 753*0b57cec5SDimitry Andric 754*0b57cec5SDimitry Andric bool operator!=(const SourceInfo &rhs) const { 755*0b57cec5SDimitry Andric return function != rhs.function || 756*0b57cec5SDimitry Andric line_entry.original_file != rhs.line_entry.original_file || 757*0b57cec5SDimitry Andric line_entry.line != rhs.line_entry.line; 758*0b57cec5SDimitry Andric } 759*0b57cec5SDimitry Andric 760*0b57cec5SDimitry Andric bool operator<(const SourceInfo &rhs) const { 761*0b57cec5SDimitry Andric if (function.GetCString() < rhs.function.GetCString()) 762*0b57cec5SDimitry Andric return true; 763*0b57cec5SDimitry Andric if (line_entry.file.GetDirectory().GetCString() < 764*0b57cec5SDimitry Andric rhs.line_entry.file.GetDirectory().GetCString()) 765*0b57cec5SDimitry Andric return true; 766*0b57cec5SDimitry Andric if (line_entry.file.GetFilename().GetCString() < 767*0b57cec5SDimitry Andric rhs.line_entry.file.GetFilename().GetCString()) 768*0b57cec5SDimitry Andric return true; 769*0b57cec5SDimitry Andric if (line_entry.line < rhs.line_entry.line) 770*0b57cec5SDimitry Andric return true; 771*0b57cec5SDimitry Andric return false; 772*0b57cec5SDimitry Andric } 773*0b57cec5SDimitry Andric }; 774*0b57cec5SDimitry Andric 775*0b57cec5SDimitry Andric size_t DisplayFunctionSource(const SymbolContext &sc, SourceInfo &source_info, 776*0b57cec5SDimitry Andric CommandReturnObject &result) { 777*0b57cec5SDimitry Andric if (!source_info.IsValid()) { 778*0b57cec5SDimitry Andric source_info.function = sc.GetFunctionName(); 779*0b57cec5SDimitry Andric source_info.line_entry = sc.GetFunctionStartLineEntry(); 780*0b57cec5SDimitry Andric } 781*0b57cec5SDimitry Andric 782*0b57cec5SDimitry Andric if (sc.function) { 783*0b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 784*0b57cec5SDimitry Andric 785*0b57cec5SDimitry Andric FileSpec start_file; 786*0b57cec5SDimitry Andric uint32_t start_line; 787*0b57cec5SDimitry Andric uint32_t end_line; 788*0b57cec5SDimitry Andric FileSpec end_file; 789*0b57cec5SDimitry Andric 790*0b57cec5SDimitry Andric if (sc.block == nullptr) { 791*0b57cec5SDimitry Andric // Not an inlined function 792*0b57cec5SDimitry Andric sc.function->GetStartLineSourceInfo(start_file, start_line); 793*0b57cec5SDimitry Andric if (start_line == 0) { 794*0b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find line information for " 795*0b57cec5SDimitry Andric "start of function: \"%s\".\n", 796*0b57cec5SDimitry Andric source_info.function.GetCString()); 797*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 798*0b57cec5SDimitry Andric return 0; 799*0b57cec5SDimitry Andric } 800*0b57cec5SDimitry Andric sc.function->GetEndLineSourceInfo(end_file, end_line); 801*0b57cec5SDimitry Andric } else { 802*0b57cec5SDimitry Andric // We have an inlined function 803*0b57cec5SDimitry Andric start_file = source_info.line_entry.file; 804*0b57cec5SDimitry Andric start_line = source_info.line_entry.line; 805*0b57cec5SDimitry Andric end_line = start_line + m_options.num_lines; 806*0b57cec5SDimitry Andric } 807*0b57cec5SDimitry Andric 808*0b57cec5SDimitry Andric // This is a little hacky, but the first line table entry for a function 809*0b57cec5SDimitry Andric // points to the "{" that starts the function block. It would be nice to 810*0b57cec5SDimitry Andric // actually get the function declaration in there too. So back up a bit, 811*0b57cec5SDimitry Andric // but not further than what you're going to display. 812*0b57cec5SDimitry Andric uint32_t extra_lines; 813*0b57cec5SDimitry Andric if (m_options.num_lines >= 10) 814*0b57cec5SDimitry Andric extra_lines = 5; 815*0b57cec5SDimitry Andric else 816*0b57cec5SDimitry Andric extra_lines = m_options.num_lines / 2; 817*0b57cec5SDimitry Andric uint32_t line_no; 818*0b57cec5SDimitry Andric if (start_line <= extra_lines) 819*0b57cec5SDimitry Andric line_no = 1; 820*0b57cec5SDimitry Andric else 821*0b57cec5SDimitry Andric line_no = start_line - extra_lines; 822*0b57cec5SDimitry Andric 823*0b57cec5SDimitry Andric // For fun, if the function is shorter than the number of lines we're 824*0b57cec5SDimitry Andric // supposed to display, only display the function... 825*0b57cec5SDimitry Andric if (end_line != 0) { 826*0b57cec5SDimitry Andric if (m_options.num_lines > end_line - line_no) 827*0b57cec5SDimitry Andric m_options.num_lines = end_line - line_no + extra_lines; 828*0b57cec5SDimitry Andric } 829*0b57cec5SDimitry Andric 830*0b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 831*0b57cec5SDimitry Andric 832*0b57cec5SDimitry Andric if (m_options.show_bp_locs) { 833*0b57cec5SDimitry Andric const bool show_inlines = true; 834*0b57cec5SDimitry Andric m_breakpoint_locations.Reset(start_file, 0, show_inlines); 835*0b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 836*0b57cec5SDimitry Andric m_exe_ctx.GetTargetSP()); 837*0b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 838*0b57cec5SDimitry Andric } 839*0b57cec5SDimitry Andric 840*0b57cec5SDimitry Andric result.AppendMessageWithFormat("File: %s\n", 841*0b57cec5SDimitry Andric start_file.GetPath().c_str()); 842*0b57cec5SDimitry Andric // We don't care about the column here. 843*0b57cec5SDimitry Andric const uint32_t column = 0; 844*0b57cec5SDimitry Andric return target->GetSourceManager().DisplaySourceLinesWithLineNumbers( 845*0b57cec5SDimitry Andric start_file, line_no, column, 0, m_options.num_lines, "", 846*0b57cec5SDimitry Andric &result.GetOutputStream(), GetBreakpointLocations()); 847*0b57cec5SDimitry Andric } else { 848*0b57cec5SDimitry Andric result.AppendErrorWithFormat( 849*0b57cec5SDimitry Andric "Could not find function info for: \"%s\".\n", 850*0b57cec5SDimitry Andric m_options.symbol_name.c_str()); 851*0b57cec5SDimitry Andric } 852*0b57cec5SDimitry Andric return 0; 853*0b57cec5SDimitry Andric } 854*0b57cec5SDimitry Andric 855*0b57cec5SDimitry Andric // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols 856*0b57cec5SDimitry Andric // functions "take a possibly empty vector of strings which are names of 857*0b57cec5SDimitry Andric // modules, and run the two search functions on the subset of the full module 858*0b57cec5SDimitry Andric // list that matches the strings in the input vector". If we wanted to put 859*0b57cec5SDimitry Andric // these somewhere, there should probably be a module-filter-list that can be 860*0b57cec5SDimitry Andric // passed to the various ModuleList::Find* calls, which would either be a 861*0b57cec5SDimitry Andric // vector of string names or a ModuleSpecList. 8629dba64beSDimitry Andric void FindMatchingFunctions(Target *target, ConstString name, 863*0b57cec5SDimitry Andric SymbolContextList &sc_list) { 864*0b57cec5SDimitry Andric // Displaying the source for a symbol: 865*0b57cec5SDimitry Andric bool include_inlines = true; 866*0b57cec5SDimitry Andric bool include_symbols = false; 867*0b57cec5SDimitry Andric 868*0b57cec5SDimitry Andric if (m_options.num_lines == 0) 869*0b57cec5SDimitry Andric m_options.num_lines = 10; 870*0b57cec5SDimitry Andric 871*0b57cec5SDimitry Andric const size_t num_modules = m_options.modules.size(); 872*0b57cec5SDimitry Andric if (num_modules > 0) { 873*0b57cec5SDimitry Andric ModuleList matching_modules; 874*0b57cec5SDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 875*0b57cec5SDimitry Andric FileSpec module_file_spec(m_options.modules[i]); 876*0b57cec5SDimitry Andric if (module_file_spec) { 877*0b57cec5SDimitry Andric ModuleSpec module_spec(module_file_spec); 878*0b57cec5SDimitry Andric matching_modules.Clear(); 879*0b57cec5SDimitry Andric target->GetImages().FindModules(module_spec, matching_modules); 880480093f4SDimitry Andric matching_modules.FindFunctions(name, eFunctionNameTypeAuto, 881480093f4SDimitry Andric include_symbols, include_inlines, 8829dba64beSDimitry Andric sc_list); 883*0b57cec5SDimitry Andric } 884*0b57cec5SDimitry Andric } 885*0b57cec5SDimitry Andric } else { 8869dba64beSDimitry Andric target->GetImages().FindFunctions(name, eFunctionNameTypeAuto, 8879dba64beSDimitry Andric include_symbols, include_inlines, 888*0b57cec5SDimitry Andric sc_list); 889*0b57cec5SDimitry Andric } 890*0b57cec5SDimitry Andric } 891*0b57cec5SDimitry Andric 8929dba64beSDimitry Andric void FindMatchingFunctionSymbols(Target *target, ConstString name, 893*0b57cec5SDimitry Andric SymbolContextList &sc_list) { 894*0b57cec5SDimitry Andric const size_t num_modules = m_options.modules.size(); 895*0b57cec5SDimitry Andric if (num_modules > 0) { 896*0b57cec5SDimitry Andric ModuleList matching_modules; 897*0b57cec5SDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 898*0b57cec5SDimitry Andric FileSpec module_file_spec(m_options.modules[i]); 899*0b57cec5SDimitry Andric if (module_file_spec) { 900*0b57cec5SDimitry Andric ModuleSpec module_spec(module_file_spec); 901*0b57cec5SDimitry Andric matching_modules.Clear(); 902*0b57cec5SDimitry Andric target->GetImages().FindModules(module_spec, matching_modules); 9039dba64beSDimitry Andric matching_modules.FindFunctionSymbols(name, eFunctionNameTypeAuto, 9049dba64beSDimitry Andric sc_list); 905*0b57cec5SDimitry Andric } 906*0b57cec5SDimitry Andric } 907*0b57cec5SDimitry Andric } else { 9089dba64beSDimitry Andric target->GetImages().FindFunctionSymbols(name, eFunctionNameTypeAuto, 9099dba64beSDimitry Andric sc_list); 910*0b57cec5SDimitry Andric } 911*0b57cec5SDimitry Andric } 912*0b57cec5SDimitry Andric 913*0b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 914*0b57cec5SDimitry Andric const size_t argc = command.GetArgumentCount(); 915*0b57cec5SDimitry Andric 916*0b57cec5SDimitry Andric if (argc != 0) { 917*0b57cec5SDimitry Andric result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", 918*0b57cec5SDimitry Andric GetCommandName().str().c_str()); 919*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 920*0b57cec5SDimitry Andric return false; 921*0b57cec5SDimitry Andric } 922*0b57cec5SDimitry Andric 923*0b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 924*0b57cec5SDimitry Andric 925*0b57cec5SDimitry Andric if (!m_options.symbol_name.empty()) { 926*0b57cec5SDimitry Andric SymbolContextList sc_list; 927*0b57cec5SDimitry Andric ConstString name(m_options.symbol_name.c_str()); 928*0b57cec5SDimitry Andric 929*0b57cec5SDimitry Andric // Displaying the source for a symbol. Search for function named name. 9309dba64beSDimitry Andric FindMatchingFunctions(target, name, sc_list); 9319dba64beSDimitry Andric size_t num_matches = sc_list.GetSize(); 932*0b57cec5SDimitry Andric if (!num_matches) { 933*0b57cec5SDimitry Andric // If we didn't find any functions with that name, try searching for 934*0b57cec5SDimitry Andric // symbols that line up exactly with function addresses. 935*0b57cec5SDimitry Andric SymbolContextList sc_list_symbols; 936*0b57cec5SDimitry Andric FindMatchingFunctionSymbols(target, name, sc_list_symbols); 9379dba64beSDimitry Andric size_t num_symbol_matches = sc_list_symbols.GetSize(); 9389dba64beSDimitry Andric 939*0b57cec5SDimitry Andric for (size_t i = 0; i < num_symbol_matches; i++) { 940*0b57cec5SDimitry Andric SymbolContext sc; 941*0b57cec5SDimitry Andric sc_list_symbols.GetContextAtIndex(i, sc); 942*0b57cec5SDimitry Andric if (sc.symbol && sc.symbol->ValueIsAddress()) { 943*0b57cec5SDimitry Andric const Address &base_address = sc.symbol->GetAddressRef(); 944*0b57cec5SDimitry Andric Function *function = base_address.CalculateSymbolContextFunction(); 945*0b57cec5SDimitry Andric if (function) { 946*0b57cec5SDimitry Andric sc_list.Append(SymbolContext(function)); 947*0b57cec5SDimitry Andric num_matches++; 948*0b57cec5SDimitry Andric break; 949*0b57cec5SDimitry Andric } 950*0b57cec5SDimitry Andric } 951*0b57cec5SDimitry Andric } 952*0b57cec5SDimitry Andric } 953*0b57cec5SDimitry Andric 954*0b57cec5SDimitry Andric if (num_matches == 0) { 955*0b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find function named: \"%s\".\n", 956*0b57cec5SDimitry Andric m_options.symbol_name.c_str()); 957*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 958*0b57cec5SDimitry Andric return false; 959*0b57cec5SDimitry Andric } 960*0b57cec5SDimitry Andric 961*0b57cec5SDimitry Andric if (num_matches > 1) { 962*0b57cec5SDimitry Andric std::set<SourceInfo> source_match_set; 963*0b57cec5SDimitry Andric 964*0b57cec5SDimitry Andric bool displayed_something = false; 965*0b57cec5SDimitry Andric for (size_t i = 0; i < num_matches; i++) { 966*0b57cec5SDimitry Andric SymbolContext sc; 967*0b57cec5SDimitry Andric sc_list.GetContextAtIndex(i, sc); 968*0b57cec5SDimitry Andric SourceInfo source_info(sc.GetFunctionName(), 969*0b57cec5SDimitry Andric sc.GetFunctionStartLineEntry()); 970*0b57cec5SDimitry Andric 971*0b57cec5SDimitry Andric if (source_info.IsValid()) { 972*0b57cec5SDimitry Andric if (source_match_set.find(source_info) == source_match_set.end()) { 973*0b57cec5SDimitry Andric source_match_set.insert(source_info); 974*0b57cec5SDimitry Andric if (DisplayFunctionSource(sc, source_info, result)) 975*0b57cec5SDimitry Andric displayed_something = true; 976*0b57cec5SDimitry Andric } 977*0b57cec5SDimitry Andric } 978*0b57cec5SDimitry Andric } 979*0b57cec5SDimitry Andric 980*0b57cec5SDimitry Andric if (displayed_something) 981*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 982*0b57cec5SDimitry Andric else 983*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 984*0b57cec5SDimitry Andric } else { 985*0b57cec5SDimitry Andric SymbolContext sc; 986*0b57cec5SDimitry Andric sc_list.GetContextAtIndex(0, sc); 987*0b57cec5SDimitry Andric SourceInfo source_info; 988*0b57cec5SDimitry Andric 989*0b57cec5SDimitry Andric if (DisplayFunctionSource(sc, source_info, result)) { 990*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 991*0b57cec5SDimitry Andric } else { 992*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 993*0b57cec5SDimitry Andric } 994*0b57cec5SDimitry Andric } 995*0b57cec5SDimitry Andric return result.Succeeded(); 996*0b57cec5SDimitry Andric } else if (m_options.address != LLDB_INVALID_ADDRESS) { 997*0b57cec5SDimitry Andric Address so_addr; 998*0b57cec5SDimitry Andric StreamString error_strm; 999*0b57cec5SDimitry Andric SymbolContextList sc_list; 1000*0b57cec5SDimitry Andric 1001*0b57cec5SDimitry Andric if (target->GetSectionLoadList().IsEmpty()) { 1002*0b57cec5SDimitry Andric // The target isn't loaded yet, we need to lookup the file address in 1003*0b57cec5SDimitry Andric // all modules 1004*0b57cec5SDimitry Andric const ModuleList &module_list = target->GetImages(); 1005*0b57cec5SDimitry Andric const size_t num_modules = module_list.GetSize(); 1006*0b57cec5SDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 1007*0b57cec5SDimitry Andric ModuleSP module_sp(module_list.GetModuleAtIndex(i)); 1008*0b57cec5SDimitry Andric if (module_sp && 1009*0b57cec5SDimitry Andric module_sp->ResolveFileAddress(m_options.address, so_addr)) { 1010*0b57cec5SDimitry Andric SymbolContext sc; 1011*0b57cec5SDimitry Andric sc.Clear(true); 1012*0b57cec5SDimitry Andric if (module_sp->ResolveSymbolContextForAddress( 1013*0b57cec5SDimitry Andric so_addr, eSymbolContextEverything, sc) & 1014*0b57cec5SDimitry Andric eSymbolContextLineEntry) 1015*0b57cec5SDimitry Andric sc_list.Append(sc); 1016*0b57cec5SDimitry Andric } 1017*0b57cec5SDimitry Andric } 1018*0b57cec5SDimitry Andric 1019*0b57cec5SDimitry Andric if (sc_list.GetSize() == 0) { 1020*0b57cec5SDimitry Andric result.AppendErrorWithFormat( 1021*0b57cec5SDimitry Andric "no modules have source information for file address 0x%" PRIx64 1022*0b57cec5SDimitry Andric ".\n", 1023*0b57cec5SDimitry Andric m_options.address); 1024*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 1025*0b57cec5SDimitry Andric return false; 1026*0b57cec5SDimitry Andric } 1027*0b57cec5SDimitry Andric } else { 1028*0b57cec5SDimitry Andric // The target has some things loaded, resolve this address to a compile 1029*0b57cec5SDimitry Andric // unit + file + line and display 1030*0b57cec5SDimitry Andric if (target->GetSectionLoadList().ResolveLoadAddress(m_options.address, 1031*0b57cec5SDimitry Andric so_addr)) { 1032*0b57cec5SDimitry Andric ModuleSP module_sp(so_addr.GetModule()); 1033*0b57cec5SDimitry Andric if (module_sp) { 1034*0b57cec5SDimitry Andric SymbolContext sc; 1035*0b57cec5SDimitry Andric sc.Clear(true); 1036*0b57cec5SDimitry Andric if (module_sp->ResolveSymbolContextForAddress( 1037*0b57cec5SDimitry Andric so_addr, eSymbolContextEverything, sc) & 1038*0b57cec5SDimitry Andric eSymbolContextLineEntry) { 1039*0b57cec5SDimitry Andric sc_list.Append(sc); 1040*0b57cec5SDimitry Andric } else { 1041*0b57cec5SDimitry Andric so_addr.Dump(&error_strm, nullptr, 1042*0b57cec5SDimitry Andric Address::DumpStyleModuleWithFileAddress); 1043*0b57cec5SDimitry Andric result.AppendErrorWithFormat("address resolves to %s, but there " 1044*0b57cec5SDimitry Andric "is no line table information " 1045*0b57cec5SDimitry Andric "available for this address.\n", 1046*0b57cec5SDimitry Andric error_strm.GetData()); 1047*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 1048*0b57cec5SDimitry Andric return false; 1049*0b57cec5SDimitry Andric } 1050*0b57cec5SDimitry Andric } 1051*0b57cec5SDimitry Andric } 1052*0b57cec5SDimitry Andric 1053*0b57cec5SDimitry Andric if (sc_list.GetSize() == 0) { 1054*0b57cec5SDimitry Andric result.AppendErrorWithFormat( 1055*0b57cec5SDimitry Andric "no modules contain load address 0x%" PRIx64 ".\n", 1056*0b57cec5SDimitry Andric m_options.address); 1057*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 1058*0b57cec5SDimitry Andric return false; 1059*0b57cec5SDimitry Andric } 1060*0b57cec5SDimitry Andric } 1061*0b57cec5SDimitry Andric uint32_t num_matches = sc_list.GetSize(); 1062*0b57cec5SDimitry Andric for (uint32_t i = 0; i < num_matches; ++i) { 1063*0b57cec5SDimitry Andric SymbolContext sc; 1064*0b57cec5SDimitry Andric sc_list.GetContextAtIndex(i, sc); 1065*0b57cec5SDimitry Andric if (sc.comp_unit) { 1066*0b57cec5SDimitry Andric if (m_options.show_bp_locs) { 1067*0b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 1068*0b57cec5SDimitry Andric const bool show_inlines = true; 1069480093f4SDimitry Andric m_breakpoint_locations.Reset(sc.comp_unit->GetPrimaryFile(), 0, 1070480093f4SDimitry Andric show_inlines); 1071*0b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 1072*0b57cec5SDimitry Andric target->shared_from_this()); 1073*0b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 1074*0b57cec5SDimitry Andric } 1075*0b57cec5SDimitry Andric 1076*0b57cec5SDimitry Andric bool show_fullpaths = true; 1077*0b57cec5SDimitry Andric bool show_module = true; 1078*0b57cec5SDimitry Andric bool show_inlined_frames = true; 1079*0b57cec5SDimitry Andric const bool show_function_arguments = true; 1080*0b57cec5SDimitry Andric const bool show_function_name = true; 1081*0b57cec5SDimitry Andric sc.DumpStopContext(&result.GetOutputStream(), 1082*0b57cec5SDimitry Andric m_exe_ctx.GetBestExecutionContextScope(), 1083*0b57cec5SDimitry Andric sc.line_entry.range.GetBaseAddress(), 1084*0b57cec5SDimitry Andric show_fullpaths, show_module, show_inlined_frames, 1085*0b57cec5SDimitry Andric show_function_arguments, show_function_name); 1086*0b57cec5SDimitry Andric result.GetOutputStream().EOL(); 1087*0b57cec5SDimitry Andric 1088*0b57cec5SDimitry Andric if (m_options.num_lines == 0) 1089*0b57cec5SDimitry Andric m_options.num_lines = 10; 1090*0b57cec5SDimitry Andric 1091*0b57cec5SDimitry Andric size_t lines_to_back_up = 1092*0b57cec5SDimitry Andric m_options.num_lines >= 10 ? 5 : m_options.num_lines / 2; 1093*0b57cec5SDimitry Andric 1094*0b57cec5SDimitry Andric const uint32_t column = 1095*0b57cec5SDimitry Andric (GetDebugger().GetStopShowColumn() != eStopShowColumnNone) 1096*0b57cec5SDimitry Andric ? sc.line_entry.column 1097*0b57cec5SDimitry Andric : 0; 1098*0b57cec5SDimitry Andric target->GetSourceManager().DisplaySourceLinesWithLineNumbers( 1099480093f4SDimitry Andric sc.comp_unit->GetPrimaryFile(), sc.line_entry.line, column, 1100480093f4SDimitry Andric lines_to_back_up, m_options.num_lines - lines_to_back_up, "->", 1101*0b57cec5SDimitry Andric &result.GetOutputStream(), GetBreakpointLocations()); 1102*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 1103*0b57cec5SDimitry Andric } 1104*0b57cec5SDimitry Andric } 1105*0b57cec5SDimitry Andric } else if (m_options.file_name.empty()) { 1106*0b57cec5SDimitry Andric // Last valid source manager context, or the current frame if no valid 1107*0b57cec5SDimitry Andric // last context in source manager. One little trick here, if you type the 1108*0b57cec5SDimitry Andric // exact same list command twice in a row, it is more likely because you 1109*0b57cec5SDimitry Andric // typed it once, then typed it again 1110*0b57cec5SDimitry Andric if (m_options.start_line == 0) { 1111*0b57cec5SDimitry Andric if (target->GetSourceManager().DisplayMoreWithLineNumbers( 1112*0b57cec5SDimitry Andric &result.GetOutputStream(), m_options.num_lines, 1113*0b57cec5SDimitry Andric m_options.reverse, GetBreakpointLocations())) { 1114*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 1115*0b57cec5SDimitry Andric } 1116*0b57cec5SDimitry Andric } else { 1117*0b57cec5SDimitry Andric if (m_options.num_lines == 0) 1118*0b57cec5SDimitry Andric m_options.num_lines = 10; 1119*0b57cec5SDimitry Andric 1120*0b57cec5SDimitry Andric if (m_options.show_bp_locs) { 1121*0b57cec5SDimitry Andric SourceManager::FileSP last_file_sp( 1122*0b57cec5SDimitry Andric target->GetSourceManager().GetLastFile()); 1123*0b57cec5SDimitry Andric if (last_file_sp) { 1124*0b57cec5SDimitry Andric const bool show_inlines = true; 1125*0b57cec5SDimitry Andric m_breakpoint_locations.Reset(last_file_sp->GetFileSpec(), 0, 1126*0b57cec5SDimitry Andric show_inlines); 1127*0b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 1128*0b57cec5SDimitry Andric target->shared_from_this()); 1129*0b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 1130*0b57cec5SDimitry Andric } 1131*0b57cec5SDimitry Andric } else 1132*0b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 1133*0b57cec5SDimitry Andric 1134*0b57cec5SDimitry Andric const uint32_t column = 0; 1135*0b57cec5SDimitry Andric if (target->GetSourceManager() 1136*0b57cec5SDimitry Andric .DisplaySourceLinesWithLineNumbersUsingLastFile( 1137*0b57cec5SDimitry Andric m_options.start_line, // Line to display 1138*0b57cec5SDimitry Andric m_options.num_lines, // Lines after line to 1139*0b57cec5SDimitry Andric UINT32_MAX, // Don't mark "line" 1140*0b57cec5SDimitry Andric column, 1141*0b57cec5SDimitry Andric "", // Don't mark "line" 1142*0b57cec5SDimitry Andric &result.GetOutputStream(), GetBreakpointLocations())) { 1143*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 1144*0b57cec5SDimitry Andric } 1145*0b57cec5SDimitry Andric } 1146*0b57cec5SDimitry Andric } else { 1147*0b57cec5SDimitry Andric const char *filename = m_options.file_name.c_str(); 1148*0b57cec5SDimitry Andric 1149*0b57cec5SDimitry Andric bool check_inlines = false; 1150*0b57cec5SDimitry Andric SymbolContextList sc_list; 1151*0b57cec5SDimitry Andric size_t num_matches = 0; 1152*0b57cec5SDimitry Andric 1153*0b57cec5SDimitry Andric if (!m_options.modules.empty()) { 1154*0b57cec5SDimitry Andric ModuleList matching_modules; 1155*0b57cec5SDimitry Andric for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) { 1156*0b57cec5SDimitry Andric FileSpec module_file_spec(m_options.modules[i]); 1157*0b57cec5SDimitry Andric if (module_file_spec) { 1158*0b57cec5SDimitry Andric ModuleSpec module_spec(module_file_spec); 1159*0b57cec5SDimitry Andric matching_modules.Clear(); 1160*0b57cec5SDimitry Andric target->GetImages().FindModules(module_spec, matching_modules); 1161*0b57cec5SDimitry Andric num_matches += matching_modules.ResolveSymbolContextForFilePath( 1162*0b57cec5SDimitry Andric filename, 0, check_inlines, 1163*0b57cec5SDimitry Andric SymbolContextItem(eSymbolContextModule | 1164*0b57cec5SDimitry Andric eSymbolContextCompUnit), 1165*0b57cec5SDimitry Andric sc_list); 1166*0b57cec5SDimitry Andric } 1167*0b57cec5SDimitry Andric } 1168*0b57cec5SDimitry Andric } else { 1169*0b57cec5SDimitry Andric num_matches = target->GetImages().ResolveSymbolContextForFilePath( 1170*0b57cec5SDimitry Andric filename, 0, check_inlines, 1171*0b57cec5SDimitry Andric eSymbolContextModule | eSymbolContextCompUnit, sc_list); 1172*0b57cec5SDimitry Andric } 1173*0b57cec5SDimitry Andric 1174*0b57cec5SDimitry Andric if (num_matches == 0) { 1175*0b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find source file \"%s\".\n", 1176*0b57cec5SDimitry Andric m_options.file_name.c_str()); 1177*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 1178*0b57cec5SDimitry Andric return false; 1179*0b57cec5SDimitry Andric } 1180*0b57cec5SDimitry Andric 1181*0b57cec5SDimitry Andric if (num_matches > 1) { 1182*0b57cec5SDimitry Andric bool got_multiple = false; 1183480093f4SDimitry Andric CompileUnit *test_cu = nullptr; 1184*0b57cec5SDimitry Andric 1185*0b57cec5SDimitry Andric for (unsigned i = 0; i < num_matches; i++) { 1186*0b57cec5SDimitry Andric SymbolContext sc; 1187*0b57cec5SDimitry Andric sc_list.GetContextAtIndex(i, sc); 1188*0b57cec5SDimitry Andric if (sc.comp_unit) { 1189480093f4SDimitry Andric if (test_cu) { 1190480093f4SDimitry Andric if (test_cu != sc.comp_unit) 1191*0b57cec5SDimitry Andric got_multiple = true; 1192*0b57cec5SDimitry Andric break; 1193*0b57cec5SDimitry Andric } else 1194480093f4SDimitry Andric test_cu = sc.comp_unit; 1195*0b57cec5SDimitry Andric } 1196*0b57cec5SDimitry Andric } 1197*0b57cec5SDimitry Andric if (got_multiple) { 1198*0b57cec5SDimitry Andric result.AppendErrorWithFormat( 1199*0b57cec5SDimitry Andric "Multiple source files found matching: \"%s.\"\n", 1200*0b57cec5SDimitry Andric m_options.file_name.c_str()); 1201*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 1202*0b57cec5SDimitry Andric return false; 1203*0b57cec5SDimitry Andric } 1204*0b57cec5SDimitry Andric } 1205*0b57cec5SDimitry Andric 1206*0b57cec5SDimitry Andric SymbolContext sc; 1207*0b57cec5SDimitry Andric if (sc_list.GetContextAtIndex(0, sc)) { 1208*0b57cec5SDimitry Andric if (sc.comp_unit) { 1209*0b57cec5SDimitry Andric if (m_options.show_bp_locs) { 1210*0b57cec5SDimitry Andric const bool show_inlines = true; 1211480093f4SDimitry Andric m_breakpoint_locations.Reset(sc.comp_unit->GetPrimaryFile(), 0, 1212480093f4SDimitry Andric show_inlines); 1213*0b57cec5SDimitry Andric SearchFilterForUnconstrainedSearches target_search_filter( 1214*0b57cec5SDimitry Andric target->shared_from_this()); 1215*0b57cec5SDimitry Andric target_search_filter.Search(m_breakpoint_locations); 1216*0b57cec5SDimitry Andric } else 1217*0b57cec5SDimitry Andric m_breakpoint_locations.Clear(); 1218*0b57cec5SDimitry Andric 1219*0b57cec5SDimitry Andric if (m_options.num_lines == 0) 1220*0b57cec5SDimitry Andric m_options.num_lines = 10; 1221*0b57cec5SDimitry Andric const uint32_t column = 0; 1222*0b57cec5SDimitry Andric target->GetSourceManager().DisplaySourceLinesWithLineNumbers( 1223480093f4SDimitry Andric sc.comp_unit->GetPrimaryFile(), m_options.start_line, column, 0, 1224480093f4SDimitry Andric m_options.num_lines, "", &result.GetOutputStream(), 1225480093f4SDimitry Andric GetBreakpointLocations()); 1226*0b57cec5SDimitry Andric 1227*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 1228*0b57cec5SDimitry Andric } else { 1229*0b57cec5SDimitry Andric result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n", 1230*0b57cec5SDimitry Andric m_options.file_name.c_str()); 1231*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 1232*0b57cec5SDimitry Andric return false; 1233*0b57cec5SDimitry Andric } 1234*0b57cec5SDimitry Andric } 1235*0b57cec5SDimitry Andric } 1236*0b57cec5SDimitry Andric return result.Succeeded(); 1237*0b57cec5SDimitry Andric } 1238*0b57cec5SDimitry Andric 1239*0b57cec5SDimitry Andric const SymbolContextList *GetBreakpointLocations() { 1240*0b57cec5SDimitry Andric if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0) 1241*0b57cec5SDimitry Andric return &m_breakpoint_locations.GetFileLineMatches(); 1242*0b57cec5SDimitry Andric return nullptr; 1243*0b57cec5SDimitry Andric } 1244*0b57cec5SDimitry Andric 1245*0b57cec5SDimitry Andric CommandOptions m_options; 1246*0b57cec5SDimitry Andric FileLineResolver m_breakpoint_locations; 1247*0b57cec5SDimitry Andric std::string m_reverse_name; 1248*0b57cec5SDimitry Andric }; 1249*0b57cec5SDimitry Andric 1250*0b57cec5SDimitry Andric #pragma mark CommandObjectMultiwordSource 1251*0b57cec5SDimitry Andric // CommandObjectMultiwordSource 1252*0b57cec5SDimitry Andric 1253*0b57cec5SDimitry Andric CommandObjectMultiwordSource::CommandObjectMultiwordSource( 1254*0b57cec5SDimitry Andric CommandInterpreter &interpreter) 1255480093f4SDimitry Andric : CommandObjectMultiword(interpreter, "source", 1256480093f4SDimitry Andric "Commands for examining " 1257*0b57cec5SDimitry Andric "source code described by " 1258*0b57cec5SDimitry Andric "debug information for the " 1259*0b57cec5SDimitry Andric "current target process.", 1260*0b57cec5SDimitry Andric "source <subcommand> [<subcommand-options>]") { 1261*0b57cec5SDimitry Andric LoadSubCommand("info", 1262*0b57cec5SDimitry Andric CommandObjectSP(new CommandObjectSourceInfo(interpreter))); 1263*0b57cec5SDimitry Andric LoadSubCommand("list", 1264*0b57cec5SDimitry Andric CommandObjectSP(new CommandObjectSourceList(interpreter))); 1265*0b57cec5SDimitry Andric } 1266*0b57cec5SDimitry Andric 1267*0b57cec5SDimitry Andric CommandObjectMultiwordSource::~CommandObjectMultiwordSource() = default; 1268