//===-- CommandObjectImage.cpp ----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "CommandObjectImage.h" // C Includes // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/Core/Debugger.h" #include "lldb/Core/FileSpec.h" #include "lldb/Core/Module.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Core/Stream.h" #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/CommandCompletions.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- // Static Helper functions //---------------------------------------------------------------------- static void DumpModuleArchitecture (Stream &strm, Module *module, uint32_t width) { if (module) { if (width) strm.Printf("%-*s", width, module->GetArchitecture().AsCString()); else strm.PutCString(module->GetArchitecture().AsCString()); } } static void DumpModuleUUID (Stream &strm, Module *module) { module->GetUUID().Dump (&strm); } static uint32_t DumpCompileUnitLineTable ( CommandInterpreter &interpreter, Stream &strm, Module *module, const FileSpec &file_spec, bool load_addresses ) { uint32_t num_matches = 0; if (module) { SymbolContextList sc_list; num_matches = module->ResolveSymbolContextsForFileSpec (file_spec, 0, false, eSymbolContextCompUnit, sc_list); for (uint32_t i=0; i 0) strm << "\n\n"; strm << "Line table for " << *dynamic_cast (sc.comp_unit) << " in `" << module->GetFileSpec().GetFilename() << "\n"; LineTable *line_table = sc.comp_unit->GetLineTable(); if (line_table) line_table->GetDescription (&strm, interpreter.GetDebugger().GetExecutionContext().target, lldb::eDescriptionLevelBrief); else strm << "No line table"; } } } return num_matches; } static void DumpFullpath (Stream &strm, const FileSpec *file_spec_ptr, uint32_t width) { if (file_spec_ptr) { if (width > 0) { char fullpath[PATH_MAX]; if (file_spec_ptr->GetPath(fullpath, sizeof(fullpath))) { strm.Printf("%-*s", width, fullpath); return; } } else { file_spec_ptr->Dump(&strm); return; } } // Keep the width spacing correct if things go wrong... if (width > 0) strm.Printf("%-*s", width, ""); } static void DumpDirectory (Stream &strm, const FileSpec *file_spec_ptr, uint32_t width) { if (file_spec_ptr) { if (width > 0) strm.Printf("%-*s", width, file_spec_ptr->GetDirectory().AsCString("")); else file_spec_ptr->GetDirectory().Dump(&strm); return; } // Keep the width spacing correct if things go wrong... if (width > 0) strm.Printf("%-*s", width, ""); } static void DumpBasename (Stream &strm, const FileSpec *file_spec_ptr, uint32_t width) { if (file_spec_ptr) { if (width > 0) strm.Printf("%-*s", width, file_spec_ptr->GetFilename().AsCString("")); else file_spec_ptr->GetFilename().Dump(&strm); return; } // Keep the width spacing correct if things go wrong... if (width > 0) strm.Printf("%-*s", width, ""); } static void DumpModuleSymtab (CommandInterpreter &interpreter, Stream &strm, Module *module) { if (module) { ObjectFile *objfile = module->GetObjectFile (); if (objfile) { Symtab *symtab = objfile->GetSymtab(); if (symtab) symtab->Dump(&strm, interpreter.GetDebugger().GetExecutionContext().target); } } } static void DumpModuleSections (CommandInterpreter &interpreter, Stream &strm, Module *module) { if (module) { ObjectFile *objfile = module->GetObjectFile (); if (objfile) { SectionList *section_list = objfile->GetSectionList(); if (section_list) section_list->Dump(&strm, interpreter.GetDebugger().GetExecutionContext().target, true); } } } static bool DumpModuleSymbolVendor (Stream &strm, Module *module) { if (module) { SymbolVendor *symbol_vendor = module->GetSymbolVendor(true); if (symbol_vendor) { symbol_vendor->Dump(&strm); return true; } } return false; } static bool LookupAddressInModule ( CommandInterpreter &interpreter, Stream &strm, Module *module, uint32_t resolve_mask, lldb::addr_t raw_addr, lldb::addr_t offset, bool verbose ) { if (module) { lldb::addr_t addr = raw_addr - offset; Address so_addr; SymbolContext sc; Target *target = interpreter.GetDebugger().GetExecutionContext().target; if (target && !target->GetSectionLoadList().IsEmpty()) { if (!target->GetSectionLoadList().ResolveLoadAddress (addr, so_addr)) return false; else if (so_addr.GetModule() != module) return false; } else { if (!module->ResolveFileAddress (addr, so_addr)) return false; } // If an offset was given, print out the address we ended up looking up if (offset) strm.Printf("0x%llx: ", addr); ExecutionContextScope *exe_scope = interpreter.GetDebugger().GetExecutionContext().GetBestExecutionContextScope(); strm.IndentMore(); strm.Indent (" Address: "); so_addr.Dump (&strm, exe_scope, Address::DumpStyleSectionNameOffset); strm.EOL(); strm.Indent (" Summary: "); so_addr.Dump (&strm, exe_scope, Address::DumpStyleResolvedDescription); strm.EOL(); // Print out detailed address information when verbose is enabled if (verbose) { if (so_addr.Dump (&strm, exe_scope, Address::DumpStyleDetailedSymbolContext)) strm.EOL(); } strm.IndentLess(); return true; } return false; } static uint32_t LookupSymbolInModule (CommandInterpreter &interpreter, Stream &strm, Module *module, const char *name, bool name_is_regex) { if (module) { SymbolContext sc; ObjectFile *objfile = module->GetObjectFile (); if (objfile) { Symtab *symtab = objfile->GetSymtab(); if (symtab) { uint32_t i; std::vector match_indexes; ConstString symbol_name (name); uint32_t num_matches = 0; if (name_is_regex) { RegularExpression name_regexp(name); num_matches = symtab->AppendSymbolIndexesMatchingRegExAndType (name_regexp, eSymbolTypeAny, match_indexes); } else { num_matches = symtab->AppendSymbolIndexesWithName (symbol_name, match_indexes); } if (num_matches > 0) { strm.Indent (); strm.Printf("%u symbols match %s'%s' in ", num_matches, name_is_regex ? "the regular expression " : "", name); DumpFullpath (strm, &module->GetFileSpec(), 0); strm.PutCString(":\n"); strm.IndentMore (); Symtab::DumpSymbolHeader (&strm); for (i=0; i < num_matches; ++i) { Symbol *symbol = symtab->SymbolAtIndex(match_indexes[i]); strm.Indent (); symbol->Dump (&strm, interpreter.GetDebugger().GetExecutionContext().target, i); } strm.IndentLess (); return num_matches; } } } } return 0; } static void DumpSymbolContextList (CommandInterpreter &interpreter, Stream &strm, SymbolContextList &sc_list, bool prepend_addr) { strm.IndentMore (); uint32_t i; const uint32_t num_matches = sc_list.GetSize(); for (i=0; iGetAddressByteSize(); if (vm_addr != LLDB_INVALID_ADDRESS) strm.Address (vm_addr, addr_size); else sc.line_entry.range.GetBaseAddress().Dump (&strm, NULL, Address::DumpStyleSectionNameOffset); strm.PutCString(" in "); } } sc.DumpStopContext(&strm, interpreter.GetDebugger().GetExecutionContext().process, sc.line_entry.range.GetBaseAddress(), true, true, false); } } strm.IndentLess (); } static uint32_t LookupFunctionInModule (CommandInterpreter &interpreter, Stream &strm, Module *module, const char *name, bool name_is_regex) { if (module && name && name[0]) { SymbolContextList sc_list; SymbolVendor *symbol_vendor = module->GetSymbolVendor(); if (symbol_vendor) { uint32_t num_matches = 0; if (name_is_regex) { RegularExpression function_name_regex (name); num_matches = symbol_vendor->FindFunctions(function_name_regex, true, sc_list); } else { ConstString function_name(name); num_matches = symbol_vendor->FindFunctions(function_name, eFunctionNameTypeBase | eFunctionNameTypeFull | eFunctionNameTypeMethod | eFunctionNameTypeSelector, true, sc_list); } if (num_matches) { strm.Indent (); strm.Printf("%u match%s found in ", num_matches, num_matches > 1 ? "es" : ""); DumpFullpath (strm, &module->GetFileSpec(), 0); strm.PutCString(":\n"); DumpSymbolContextList (interpreter, strm, sc_list, true); } return num_matches; } } return 0; } static uint32_t LookupTypeInModule ( CommandInterpreter &interpreter, Stream &strm, Module *module, const char *name_cstr, bool name_is_regex ) { if (module && name_cstr && name_cstr[0]) { SymbolContextList sc_list; SymbolVendor *symbol_vendor = module->GetSymbolVendor(); if (symbol_vendor) { TypeList type_list; uint32_t num_matches = 0; SymbolContext sc; // if (name_is_regex) // { // RegularExpression name_regex (name_cstr); // num_matches = symbol_vendor->FindFunctions(sc, name_regex, true, UINT32_MAX, type_list); // } // else // { ConstString name(name_cstr); num_matches = symbol_vendor->FindTypes(sc, name, true, UINT32_MAX, type_list); // } if (num_matches) { strm.Indent (); strm.Printf("%u match%s found in ", num_matches, num_matches > 1 ? "es" : ""); DumpFullpath (strm, &module->GetFileSpec(), 0); strm.PutCString(":\n"); const uint32_t num_types = type_list.GetSize(); for (uint32_t i=0; iGetClangType (); type_sp->GetDescription (&strm, eDescriptionLevelFull, true); } strm.EOL(); } } return num_matches; } } return 0; } static uint32_t LookupFileAndLineInModule (CommandInterpreter &interpreter, Stream &strm, Module *module, const FileSpec &file_spec, uint32_t line, bool check_inlines) { if (module && file_spec) { SymbolContextList sc_list; const uint32_t num_matches = module->ResolveSymbolContextsForFileSpec(file_spec, line, check_inlines, eSymbolContextEverything, sc_list); if (num_matches > 0) { strm.Indent (); strm.Printf("%u match%s found in ", num_matches, num_matches > 1 ? "es" : ""); strm << file_spec; if (line > 0) strm.Printf (":%u", line); strm << " in "; DumpFullpath (strm, &module->GetFileSpec(), 0); strm.PutCString(":\n"); DumpSymbolContextList (interpreter, strm, sc_list, true); return num_matches; } } return 0; } //---------------------------------------------------------------------- // Image symbol table dumping command //---------------------------------------------------------------------- class CommandObjectImageDumpModuleList : public CommandObject { public: CommandObjectImageDumpModuleList (CommandInterpreter &interpreter, const char *name, const char *help, const char *syntax) : CommandObject (interpreter, name, help, syntax) { } virtual ~CommandObjectImageDumpModuleList () { } virtual int HandleArgumentCompletion (Args &input, int &cursor_index, int &cursor_char_position, OptionElementVector &opt_element_vector, int match_start_point, int max_return_elements, bool &word_complete, StringList &matches) { // Arguments are the standard module completer. std::string completion_str (input.GetArgumentAtIndex(cursor_index)); completion_str.erase (cursor_char_position); CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter, CommandCompletions::eModuleCompletion, completion_str.c_str(), match_start_point, max_return_elements, NULL, word_complete, matches); return matches.GetSize(); } }; class CommandObjectImageDumpSourceFileList : public CommandObject { public: CommandObjectImageDumpSourceFileList (CommandInterpreter &interpreter, const char *name, const char *help, const char *syntax) : CommandObject (interpreter, name, help, syntax) { } virtual ~CommandObjectImageDumpSourceFileList () { } virtual int HandleArgumentCompletion (Args &input, int &cursor_index, int &cursor_char_position, OptionElementVector &opt_element_vector, int match_start_point, int max_return_elements, bool &word_complete, StringList &matches) { // Arguments are the standard source file completer. std::string completion_str (input.GetArgumentAtIndex(cursor_index)); completion_str.erase (cursor_char_position); CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter, CommandCompletions::eSourceFileCompletion, completion_str.c_str(), match_start_point, max_return_elements, NULL, word_complete, matches); return matches.GetSize(); } }; class CommandObjectImageDumpSymtab : public CommandObjectImageDumpModuleList { public: CommandObjectImageDumpSymtab (CommandInterpreter &interpreter) : CommandObjectImageDumpModuleList (interpreter, "image dump symtab", "Dump the symbol table from one or more executable images.", "image dump symtab [ ...]") { } virtual ~CommandObjectImageDumpSymtab () { } virtual bool Execute (Args& command, CommandReturnObject &result) { Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); if (target == NULL) { result.AppendError ("invalid target, set executable file using 'file' command"); result.SetStatus (eReturnStatusFailed); return false; } else { uint32_t num_dumped = 0; uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); result.GetOutputStream().SetAddressByteSize(addr_byte_size); result.GetErrorStream().SetAddressByteSize(addr_byte_size); if (command.GetArgumentCount() == 0) { // Dump all sections for all modules images const uint32_t num_modules = target->GetImages().GetSize(); if (num_modules > 0) { result.GetOutputStream().Printf("Dumping symbol table for %u modules.\n", num_modules); for (uint32_t image_idx = 0; image_idxGetImages().GetModulePointerAtIndex(image_idx)); } } else { result.AppendError ("the target has no associated executable images"); result.SetStatus (eReturnStatusFailed); return false; } } else { // Dump specified images (by basename or fullpath) const char *arg_cstr; for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx) { FileSpec image_file(arg_cstr); ModuleList matching_modules; size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules); // Not found in our module list for our target, check the main // shared module list in case it is a extra file used somewhere // else if (num_matching_modules == 0) num_matching_modules = ModuleList::FindSharedModules (image_file, target->GetArchitecture(), NULL, NULL, matching_modules); if (num_matching_modules > 0) { for (size_t i=0; i 0) result.SetStatus (eReturnStatusSuccessFinishResult); else { result.AppendError ("no matching executable images found"); result.SetStatus (eReturnStatusFailed); } } return result.Succeeded(); } }; //---------------------------------------------------------------------- // Image section dumping command //---------------------------------------------------------------------- class CommandObjectImageDumpSections : public CommandObjectImageDumpModuleList { public: CommandObjectImageDumpSections (CommandInterpreter &interpreter) : CommandObjectImageDumpModuleList (interpreter, "image dump sections", "Dump the sections from one or more executable images.", "image dump sections [ ...]") { } virtual ~CommandObjectImageDumpSections () { } virtual bool Execute (Args& command, CommandReturnObject &result) { Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); if (target == NULL) { result.AppendError ("invalid target, set executable file using 'file' command"); result.SetStatus (eReturnStatusFailed); return false; } else { uint32_t num_dumped = 0; uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); result.GetOutputStream().SetAddressByteSize(addr_byte_size); result.GetErrorStream().SetAddressByteSize(addr_byte_size); if (command.GetArgumentCount() == 0) { // Dump all sections for all modules images const uint32_t num_modules = target->GetImages().GetSize(); if (num_modules > 0) { result.GetOutputStream().Printf("Dumping sections for %u modules.\n", num_modules); for (uint32_t image_idx = 0; image_idxGetImages().GetModulePointerAtIndex(image_idx)); } } else { result.AppendError ("the target has no associated executable images"); result.SetStatus (eReturnStatusFailed); return false; } } else { // Dump specified images (by basename or fullpath) const char *arg_cstr; for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx) { FileSpec image_file(arg_cstr); ModuleList matching_modules; size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules); // Not found in our module list for our target, check the main // shared module list in case it is a extra file used somewhere // else if (num_matching_modules == 0) num_matching_modules = ModuleList::FindSharedModules (image_file, target->GetArchitecture(), NULL, NULL, matching_modules); if (num_matching_modules > 0) { for (size_t i=0; i 0) result.SetStatus (eReturnStatusSuccessFinishResult); else { result.AppendError ("no matching executable images found"); result.SetStatus (eReturnStatusFailed); } } return result.Succeeded(); } }; //---------------------------------------------------------------------- // Image debug symbol dumping command //---------------------------------------------------------------------- class CommandObjectImageDumpSymfile : public CommandObjectImageDumpModuleList { public: CommandObjectImageDumpSymfile (CommandInterpreter &interpreter) : CommandObjectImageDumpModuleList (interpreter, "image dump symfile", "Dump the debug symbol file for one or more executable images.", "image dump symfile [ ...]") { } virtual ~CommandObjectImageDumpSymfile () { } virtual bool Execute (Args& command, CommandReturnObject &result) { Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); if (target == NULL) { result.AppendError ("invalid target, set executable file using 'file' command"); result.SetStatus (eReturnStatusFailed); return false; } else { uint32_t num_dumped = 0; uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); result.GetOutputStream().SetAddressByteSize(addr_byte_size); result.GetErrorStream().SetAddressByteSize(addr_byte_size); if (command.GetArgumentCount() == 0) { // Dump all sections for all modules images const uint32_t num_modules = target->GetImages().GetSize(); if (num_modules > 0) { result.GetOutputStream().Printf("Dumping debug symbols for %u modules.\n", num_modules); for (uint32_t image_idx = 0; image_idxGetImages().GetModulePointerAtIndex(image_idx))) num_dumped++; } } else { result.AppendError ("the target has no associated executable images"); result.SetStatus (eReturnStatusFailed); return false; } } else { // Dump specified images (by basename or fullpath) const char *arg_cstr; for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx) { FileSpec image_file(arg_cstr); ModuleList matching_modules; size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules); // Not found in our module list for our target, check the main // shared module list in case it is a extra file used somewhere // else if (num_matching_modules == 0) num_matching_modules = ModuleList::FindSharedModules (image_file, target->GetArchitecture(), NULL, NULL, matching_modules); if (num_matching_modules > 0) { for (size_t i=0; i 0) result.SetStatus (eReturnStatusSuccessFinishResult); else { result.AppendError ("no matching executable images found"); result.SetStatus (eReturnStatusFailed); } } return result.Succeeded(); } }; //---------------------------------------------------------------------- // Image debug symbol dumping command //---------------------------------------------------------------------- class CommandObjectImageDumpLineTable : public CommandObjectImageDumpSourceFileList { public: CommandObjectImageDumpLineTable (CommandInterpreter &interpreter) : CommandObjectImageDumpSourceFileList (interpreter, "image dump line-table", "Dump the debug symbol file for one or more executable images.", "image dump line-table [ ...]") { } virtual ~CommandObjectImageDumpLineTable () { } virtual bool Execute (Args& command, CommandReturnObject &result) { Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); if (target == NULL) { result.AppendError ("invalid target, set executable file using 'file' command"); result.SetStatus (eReturnStatusFailed); return false; } else { ExecutionContext exe_ctx(m_interpreter.GetDebugger().GetExecutionContext()); uint32_t total_num_dumped = 0; uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); result.GetOutputStream().SetAddressByteSize(addr_byte_size); result.GetErrorStream().SetAddressByteSize(addr_byte_size); if (command.GetArgumentCount() == 0) { result.AppendErrorWithFormat ("\nSyntax: %s\n", m_cmd_syntax.c_str()); result.SetStatus (eReturnStatusFailed); } else { // Dump specified images (by basename or fullpath) const char *arg_cstr; for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx) { FileSpec file_spec(arg_cstr); const uint32_t num_modules = target->GetImages().GetSize(); if (num_modules > 0) { uint32_t num_dumped = 0; for (uint32_t i = 0; iGetImages().GetModulePointerAtIndex(i), file_spec, exe_ctx.process != NULL && exe_ctx.process->IsAlive())) num_dumped++; } if (num_dumped == 0) result.AppendWarningWithFormat ("No source filenames matched '%s'.\n", arg_cstr); else total_num_dumped += num_dumped; } } } if (total_num_dumped > 0) result.SetStatus (eReturnStatusSuccessFinishResult); else { result.AppendError ("no source filenames matched any command arguments"); result.SetStatus (eReturnStatusFailed); } } return result.Succeeded(); } }; //---------------------------------------------------------------------- // Dump multi-word command //---------------------------------------------------------------------- class CommandObjectImageDump : public CommandObjectMultiword { public: //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ CommandObjectImageDump(CommandInterpreter &interpreter) : CommandObjectMultiword (interpreter, "image dump", "A set of commands for dumping information about one or more executable images; 'line-table' expects a source file name", "image dump [symtab|sections|symfile|line-table] [ ...]") { LoadSubCommand ("symtab", CommandObjectSP (new CommandObjectImageDumpSymtab (interpreter))); LoadSubCommand ("sections", CommandObjectSP (new CommandObjectImageDumpSections (interpreter))); LoadSubCommand ("symfile", CommandObjectSP (new CommandObjectImageDumpSymfile (interpreter))); LoadSubCommand ("line-table", CommandObjectSP (new CommandObjectImageDumpLineTable (interpreter))); } virtual ~CommandObjectImageDump() { } }; //---------------------------------------------------------------------- // List images with associated information //---------------------------------------------------------------------- class CommandObjectImageList : public CommandObject { public: class CommandOptions : public Options { public: CommandOptions () : Options(), m_format_array() { } virtual ~CommandOptions () { } virtual Error SetOptionValue (int option_idx, const char *option_arg) { char short_option = (char) m_getopt_table[option_idx].val; uint32_t width = 0; if (option_arg) width = strtoul (option_arg, NULL, 0); m_format_array.push_back(std::make_pair(short_option, width)); Error error; return error; } void ResetOptionValues () { Options::ResetOptionValues(); m_format_array.clear(); } const lldb::OptionDefinition* GetDefinitions () { return g_option_table; } // Options table: Required for subclasses of Options. static lldb::OptionDefinition g_option_table[]; // Instance variables to hold the values for command options. typedef std::vector< std::pair > FormatWidthCollection; FormatWidthCollection m_format_array; }; CommandObjectImageList (CommandInterpreter &interpreter) : CommandObject (interpreter, "image list", "List current executable and dependent shared library images.", "image list []") { } virtual ~CommandObjectImageList () { } virtual Options * GetOptions () { return &m_options; } virtual bool Execute (Args& command, CommandReturnObject &result) { Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); if (target == NULL) { result.AppendError ("invalid target, set executable file using 'file' command"); result.SetStatus (eReturnStatusFailed); return false; } else { uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); result.GetOutputStream().SetAddressByteSize(addr_byte_size); result.GetErrorStream().SetAddressByteSize(addr_byte_size); // Dump all sections for all modules images const uint32_t num_modules = target->GetImages().GetSize(); if (num_modules > 0) { Stream &strm = result.GetOutputStream(); for (uint32_t image_idx = 0; image_idxGetImages().GetModulePointerAtIndex(image_idx); strm.Printf("[%3u] ", image_idx); if (m_options.m_format_array.empty()) { DumpFullpath(strm, &module->GetFileSpec(), 0); } else { const size_t num_entries = m_options.m_format_array.size(); for (size_t i=0; i 0) strm.PutChar(' '); char format_char = m_options.m_format_array[i].first; uint32_t width = m_options.m_format_array[i].second; switch (format_char) { case 'a': DumpModuleArchitecture (strm, module, width); break; case 'f': DumpFullpath (strm, &module->GetFileSpec(), width); break; case 'd': DumpDirectory (strm, &module->GetFileSpec(), width); break; case 'b': DumpBasename (strm, &module->GetFileSpec(), width); break; case 's': case 'S': { SymbolVendor *symbol_vendor = module->GetSymbolVendor(); if (symbol_vendor) { SymbolFile *symbol_file = symbol_vendor->GetSymbolFile(); if (symbol_file) { if (format_char == 'S') DumpBasename(strm, &symbol_file->GetObjectFile()->GetFileSpec(), width); else DumpFullpath (strm, &symbol_file->GetObjectFile()->GetFileSpec(), width); break; } } strm.Printf("%.*s", width, ""); } break; case 'u': DumpModuleUUID(strm, module); break; default: break; } } } strm.EOL(); } result.SetStatus (eReturnStatusSuccessFinishResult); } else { result.AppendError ("the target has no associated executable images"); result.SetStatus (eReturnStatusFailed); return false; } } return result.Succeeded(); } protected: CommandOptions m_options; }; lldb::OptionDefinition CommandObjectImageList::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_1, false, "arch", 'a', optional_argument, NULL, 0, eArgTypeWidth, "Display the architecture when listing images."}, { LLDB_OPT_SET_1, false, "uuid", 'u', no_argument, NULL, 0, eArgTypeNone, "Display the UUID when listing images."}, { LLDB_OPT_SET_1, false, "fullpath", 'f', optional_argument, NULL, 0, eArgTypeWidth, "Display the fullpath to the image object file."}, { LLDB_OPT_SET_1, false, "directory", 'd', optional_argument, NULL, 0, eArgTypeWidth, "Display the directory with optional width for the image object file."}, { LLDB_OPT_SET_1, false, "basename", 'b', optional_argument, NULL, 0, eArgTypeWidth, "Display the basename with optional width for the image object file."}, { LLDB_OPT_SET_1, false, "symfile", 's', optional_argument, NULL, 0, eArgTypeWidth, "Display the fullpath to the image symbol file with optional width."}, { LLDB_OPT_SET_1, false, "symfile-basename", 'S', optional_argument, NULL, 0, eArgTypeWidth, "Display the basename to the image symbol file with optional width."}, { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } }; //---------------------------------------------------------------------- // Lookup information in images //---------------------------------------------------------------------- class CommandObjectImageLookup : public CommandObject { public: enum { eLookupTypeInvalid = -1, eLookupTypeAddress = 0, eLookupTypeSymbol, eLookupTypeFileLine, // Line is optional eLookupTypeFunction, eLookupTypeType, kNumLookupTypes }; class CommandOptions : public Options { public: CommandOptions () : Options() { ResetOptionValues(); } virtual ~CommandOptions () { } virtual Error SetOptionValue (int option_idx, const char *option_arg) { Error error; char short_option = (char) m_getopt_table[option_idx].val; switch (short_option) { case 'a': m_type = eLookupTypeAddress; m_addr = Args::StringToUInt64(option_arg, LLDB_INVALID_ADDRESS); if (m_addr == LLDB_INVALID_ADDRESS) error.SetErrorStringWithFormat ("Invalid address string '%s'.\n", option_arg); break; case 'o': m_offset = Args::StringToUInt64(option_arg, LLDB_INVALID_ADDRESS); if (m_offset == LLDB_INVALID_ADDRESS) error.SetErrorStringWithFormat ("Invalid offset string '%s'.\n", option_arg); break; case 's': m_str = option_arg; m_type = eLookupTypeSymbol; break; case 'f': m_file.SetFile (option_arg); m_type = eLookupTypeFileLine; break; case 'i': m_check_inlines = false; break; case 'l': m_line_number = Args::StringToUInt32(option_arg, UINT32_MAX); if (m_line_number == UINT32_MAX) error.SetErrorStringWithFormat ("Invalid line number string '%s'.\n", option_arg); else if (m_line_number == 0) error.SetErrorString ("Zero is an invalid line number."); m_type = eLookupTypeFileLine; break; case 'n': m_str = option_arg; m_type = eLookupTypeFunction; break; case 't': m_str = option_arg; m_type = eLookupTypeType; break; case 'v': m_verbose = 1; break; case 'r': m_use_regex = true; break; } return error; } void ResetOptionValues () { Options::ResetOptionValues(); m_type = eLookupTypeInvalid; m_str.clear(); m_file.Clear(); m_addr = LLDB_INVALID_ADDRESS; m_offset = 0; m_line_number = 0; m_use_regex = false; m_check_inlines = true; m_verbose = false; } const lldb::OptionDefinition* GetDefinitions () { return g_option_table; } // Options table: Required for subclasses of Options. static lldb::OptionDefinition g_option_table[]; int m_type; // Should be a eLookupTypeXXX enum after parsing options std::string m_str; // Holds name lookup FileSpec m_file; // Files for file lookups lldb::addr_t m_addr; // Holds the address to lookup lldb::addr_t m_offset; // Subtract this offset from m_addr before doing lookups. uint32_t m_line_number; // Line number for file+line lookups bool m_use_regex; // Name lookups in m_str are regular expressions. bool m_check_inlines;// Check for inline entries when looking up by file/line. bool m_verbose; // Enable verbose lookup info }; CommandObjectImageLookup (CommandInterpreter &interpreter) : CommandObject (interpreter, "image lookup", "Look up information within executable and dependent shared library images.", "image lookup [] [...]") { } virtual ~CommandObjectImageLookup () { } virtual Options * GetOptions () { return &m_options; } bool LookupInModule (CommandInterpreter &interpreter, Module *module, CommandReturnObject &result, bool &syntax_error) { switch (m_options.m_type) { case eLookupTypeAddress: if (m_options.m_addr != LLDB_INVALID_ADDRESS) { if (LookupAddressInModule (m_interpreter, result.GetOutputStream(), module, eSymbolContextEverything, m_options.m_addr, m_options.m_offset, m_options.m_verbose)) { result.SetStatus(eReturnStatusSuccessFinishResult); return true; } } break; case eLookupTypeSymbol: if (!m_options.m_str.empty()) { if (LookupSymbolInModule (m_interpreter, result.GetOutputStream(), module, m_options.m_str.c_str(), m_options.m_use_regex)) { result.SetStatus(eReturnStatusSuccessFinishResult); return true; } } break; case eLookupTypeFileLine: if (m_options.m_file) { if (LookupFileAndLineInModule (m_interpreter, result.GetOutputStream(), module, m_options.m_file, m_options.m_line_number, m_options.m_check_inlines)) { result.SetStatus(eReturnStatusSuccessFinishResult); return true; } } break; case eLookupTypeFunction: if (!m_options.m_str.empty()) { if (LookupFunctionInModule (m_interpreter, result.GetOutputStream(), module, m_options.m_str.c_str(), m_options.m_use_regex)) { result.SetStatus(eReturnStatusSuccessFinishResult); return true; } } break; case eLookupTypeType: if (!m_options.m_str.empty()) { if (LookupTypeInModule (m_interpreter, result.GetOutputStream(), module, m_options.m_str.c_str(), m_options.m_use_regex)) { result.SetStatus(eReturnStatusSuccessFinishResult); return true; } } break; default: m_options.GenerateOptionUsage (m_interpreter, result.GetErrorStream(), this); syntax_error = true; break; } result.SetStatus (eReturnStatusFailed); return false; } virtual bool Execute (Args& command, CommandReturnObject &result) { Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); if (target == NULL) { result.AppendError ("invalid target, set executable file using 'file' command"); result.SetStatus (eReturnStatusFailed); return false; } else { bool syntax_error = false; uint32_t i; uint32_t num_successful_lookups = 0; uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); result.GetOutputStream().SetAddressByteSize(addr_byte_size); result.GetErrorStream().SetAddressByteSize(addr_byte_size); // Dump all sections for all modules images if (command.GetArgumentCount() == 0) { // Dump all sections for all modules images const uint32_t num_modules = target->GetImages().GetSize(); if (num_modules > 0) { for (i = 0; iGetImages().GetModulePointerAtIndex(i), result, syntax_error)) { result.GetOutputStream().EOL(); num_successful_lookups++; } } } else { result.AppendError ("the target has no associated executable images"); result.SetStatus (eReturnStatusFailed); return false; } } else { // Dump specified images (by basename or fullpath) const char *arg_cstr; for (i = 0; (arg_cstr = command.GetArgumentAtIndex(i)) != NULL && syntax_error == false; ++i) { FileSpec image_file(arg_cstr); ModuleList matching_modules; size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules); // Not found in our module list for our target, check the main // shared module list in case it is a extra file used somewhere // else if (num_matching_modules == 0) num_matching_modules = ModuleList::FindSharedModules (image_file, target->GetArchitecture(), NULL, NULL, matching_modules); if (num_matching_modules > 0) { for (size_t j=0; j 0) result.SetStatus (eReturnStatusSuccessFinishResult); else result.SetStatus (eReturnStatusFailed); } return result.Succeeded(); } protected: CommandOptions m_options; }; lldb::OptionDefinition CommandObjectImageLookup::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_1, true, "address", 'a', required_argument, NULL, 0, eArgTypeAddress, "Lookup an address in one or more executable images."}, { LLDB_OPT_SET_1, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset, "When looking up an address subtract from any addresses before doing the lookup."}, { LLDB_OPT_SET_2, true, "symbol", 's', required_argument, NULL, 0, eArgTypeSymbol, "Lookup a symbol by name in the symbol tables in one or more executable images."}, { LLDB_OPT_SET_2, false, "regex", 'r', no_argument, NULL, 0, eArgTypeNone, "The argument for name lookups are regular expressions."}, { LLDB_OPT_SET_3, true, "file", 'f', required_argument, NULL, 0, eArgTypeFilename, "Lookup a file by fullpath or basename in one or more executable images."}, { LLDB_OPT_SET_3, false, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum, "Lookup a line number in a file (must be used in conjunction with --file)."}, { LLDB_OPT_SET_3, false, "no-inlines", 'i', no_argument, NULL, 0, eArgTypeNone, "Check inline line entries (must be used in conjunction with --file)."}, { LLDB_OPT_SET_4, true, "function", 'n', required_argument, NULL, 0, eArgTypeFunctionName, "Lookup a function by name in the debug symbols in one or more executable images."}, { LLDB_OPT_SET_5, true, "type", 't', required_argument, NULL, 0, eArgTypeName, "Lookup a type by name in the debug symbols in one or more executable images."}, { LLDB_OPT_SET_ALL, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone, "Enable verbose lookup information."}, { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } }; //---------------------------------------------------------------------- // CommandObjectImage constructor //---------------------------------------------------------------------- CommandObjectImage::CommandObjectImage(CommandInterpreter &interpreter) : CommandObjectMultiword (interpreter, "image", "A set of commands for accessing information for one or more executable images.", "image ...") { LoadSubCommand ("dump", CommandObjectSP (new CommandObjectImageDump (interpreter))); LoadSubCommand ("list", CommandObjectSP (new CommandObjectImageList (interpreter))); LoadSubCommand ("lookup", CommandObjectSP (new CommandObjectImageLookup (interpreter))); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- CommandObjectImage::~CommandObjectImage() { }