diff options
Diffstat (limited to 'lldb/source/Commands/CommandObjectImage.cpp')
-rw-r--r-- | lldb/source/Commands/CommandObjectImage.cpp | 1419 |
1 files changed, 1419 insertions, 0 deletions
diff --git a/lldb/source/Commands/CommandObjectImage.cpp b/lldb/source/Commands/CommandObjectImage.cpp new file mode 100644 index 00000000000..ab728e9d32d --- /dev/null +++ b/lldb/source/Commands/CommandObjectImage.cpp @@ -0,0 +1,1419 @@ +//===-- 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/Args.h" +#include "lldb/Interpreter/CommandContext.h" +#include "lldb/Core/Options.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Core/FileSpec.h" +#include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Core/Stream.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Core/Module.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Interpreter/CommandCompletions.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 +( + CommandContext *context, + 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<num_matches; ++i) + { + SymbolContext sc; + if (sc_list.GetContextAtIndex(i, sc)) + { + if (i > 0) + strm << "\n\n"; + + strm << "Line table for " << *dynamic_cast<FileSpec*> (sc.comp_unit) << " in `" + << module->GetFileSpec().GetFilename() << "\n"; + LineTable *line_table = sc.comp_unit->GetLineTable(); + if (line_table) + line_table->GetDescription (&strm, context->GetExecutionContext().process, 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 (CommandContext *context, Stream &strm, Module *module) +{ + if (module) + { + ObjectFile *objfile = module->GetObjectFile (); + if (objfile) + { + Symtab *symtab = objfile->GetSymtab(); + if (symtab) + symtab->Dump(&strm, context->GetExecutionContext().process); + } + } +} + +static void +DumpModuleSections (CommandContext *context, Stream &strm, Module *module) +{ + if (module) + { + ObjectFile *objfile = module->GetObjectFile (); + if (objfile) + { + SectionList *section_list = objfile->GetSectionList(); + if (section_list) + section_list->Dump(&strm, context->GetExecutionContext().process, 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 (CommandContext *context, Stream &strm, Module *module, uint32_t resolve_mask, lldb::addr_t raw_addr, lldb::addr_t offset) +{ + if (module) + { + lldb::addr_t addr = raw_addr - offset; + Address so_addr; + SymbolContext sc; + Process *process = context->GetExecutionContext().process; + if (process && process->IsAlive()) + { + if (!process->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 = context->GetExecutionContext().GetBestExecutionContextScope(); + if (so_addr.Dump (&strm, exe_scope, Address::DumpStyleSectionNameOffset)) + strm.PutCString(": "); + so_addr.Dump (&strm, exe_scope, Address::DumpStyleResolvedDescription); + return true; + } + + return false; +} + +static uint32_t +LookupSymbolInModule (CommandContext *context, 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<uint32_t> 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, context->GetExecutionContext().process, i); + } + strm.IndentLess (); + return num_matches; + } + } + } + } + return 0; +} + + +static void +DumpSymbolContextList (CommandContext *context, Stream &strm, SymbolContextList &sc_list, bool prepend_addr) +{ + strm.IndentMore (); + uint32_t i; + const uint32_t num_matches = sc_list.GetSize(); + + for (i=0; i<num_matches; ++i) + { + SymbolContext sc; + if (sc_list.GetContextAtIndex(i, sc)) + { + strm.Indent(); + if (prepend_addr) + { + if (sc.line_entry.range.GetBaseAddress().IsValid()) + { + lldb::addr_t vm_addr = + sc.line_entry.range.GetBaseAddress().GetLoadAddress(context->GetExecutionContext().process); + int addr_size = sizeof (addr_t); + Process *process = context->GetExecutionContext().process; + if (process) + addr_size = process->GetAddressByteSize(); + 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, context->GetExecutionContext().process, sc.line_entry.range.GetBaseAddress()); + } + } + strm.IndentLess (); +} + +static uint32_t +LookupFunctionInModule (CommandContext *context, 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, 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 (context, strm, sc_list, true); + } + return num_matches; + } + } + return 0; +} + +static uint32_t +LookupFileAndLineInModule (CommandContext *context, 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 (context, strm, sc_list, true); + return num_matches; + } + } + return 0; + +} + + +//---------------------------------------------------------------------- +// Image symbol table dumping command +//---------------------------------------------------------------------- + +class CommandObjectImageDumpModuleList : public CommandObject +{ +public: + + CommandObjectImageDumpModuleList (const char *name, + const char *help, + const char *syntax) : + CommandObject (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, + CommandInterpreter *interpreter, + StringList &matches) + { + // Arguments are the standard module completer. + std::string completion_str (input.GetArgumentAtIndex(cursor_index)); + completion_str.erase (cursor_char_position); + + CommandCompletions::InvokeCommonCompletionCallbacks (CommandCompletions::eModuleCompletion, + completion_str.c_str(), + match_start_point, + max_return_elements, + interpreter, + NULL, + matches); + return matches.GetSize(); + } +}; + +class CommandObjectImageDumpSourceFileList : public CommandObject +{ +public: + + CommandObjectImageDumpSourceFileList (const char *name, + const char *help, + const char *syntax) : + CommandObject (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, + CommandInterpreter *interpreter, + 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 (CommandCompletions::eSourceFileCompletion, + completion_str.c_str(), + match_start_point, + max_return_elements, + interpreter, + NULL, + matches); + return matches.GetSize(); + } +}; + + +class CommandObjectImageDumpSymtab : public CommandObjectImageDumpModuleList +{ +public: + CommandObjectImageDumpSymtab () : + CommandObjectImageDumpModuleList ("image dump symtab", + "Dump the symbol table from one or more executable images.", + "image dump symtab [<file1> ...]") + { + } + + virtual + ~CommandObjectImageDumpSymtab () + { + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target *target = context->GetTarget(); + 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_idx<num_modules; ++image_idx) + { + num_dumped++; + DumpModuleSymtab (context, result.GetOutputStream(), target->GetImages().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; + const size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules); + + if (num_matching_modules > 0) + { + for (size_t i=0; i<num_matching_modules; ++i) + { + Module *image_module = matching_modules.GetModulePointerAtIndex(i); + if (image_module) + { + num_dumped++; + DumpModuleSymtab (context, result.GetOutputStream(), image_module); + } + } + } + else + result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr); + } + } + + if (num_dumped > 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 () : + CommandObjectImageDumpModuleList ( + "image dump sections", + "Dump the sections from one or more executable images.", + "image dump sections [<file1> ...]") + { + } + + virtual + ~CommandObjectImageDumpSections () + { + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target *target = context->GetTarget(); + 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_idx<num_modules; ++image_idx) + { + num_dumped++; + DumpModuleSections (context, result.GetOutputStream(), target->GetImages().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; + const size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules); + + if (num_matching_modules > 0) + { + for (size_t i=0; i<num_matching_modules; ++i) + { + Module * image_module = matching_modules.GetModulePointerAtIndex(i); + if (image_module) + { + num_dumped++; + DumpModuleSections (context, result.GetOutputStream(), image_module); + } + } + } + else + result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr); + } + } + + if (num_dumped > 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 () : + CommandObjectImageDumpModuleList ("image dump symfile", + "Dump the debug symbol file for one or more executable images.", + "image dump symfile [<file1> ...]") + { + } + + virtual + ~CommandObjectImageDumpSymfile () + { + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target *target = context->GetTarget(); + 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_idx<num_modules; ++image_idx) + { + if (DumpModuleSymbolVendor (result.GetOutputStream(), target->GetImages().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; + const size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules); + + if (num_matching_modules > 0) + { + for (size_t i=0; i<num_matching_modules; ++i) + { + Module * image_module = matching_modules.GetModulePointerAtIndex(i); + if (image_module) + { + if (DumpModuleSymbolVendor (result.GetOutputStream(), image_module)) + num_dumped++; + } + } + } + else + result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr); + } + } + + if (num_dumped > 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 () : + CommandObjectImageDumpSourceFileList ("image dump line-table", + "Dump the debug symbol file for one or more executable images.", + "image dump line-table <file1> [<file2> ...]") + { + } + + virtual + ~CommandObjectImageDumpLineTable () + { + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target *target = context->GetTarget(); + if (target == NULL) + { + result.AppendError ("invalid target, set executable file using 'file' command"); + result.SetStatus (eReturnStatusFailed); + return false; + } + else + { + ExecutionContext exe_ctx(context->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; i<num_modules; ++i) + { + if (DumpCompileUnitLineTable (context, + result.GetOutputStream(), + target->GetImages().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 ("image dump", + "Dumps information in one or more executable images; 'line-table' expects a source file name", + "image dump [symtab|sections|symfile|line-table] [<file1> <file2> ...]") + { + LoadSubCommand (CommandObjectSP (new CommandObjectImageDumpSymtab ()), "symtab", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectImageDumpSections ()), "sections", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectImageDumpSymfile ()), "symfile", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectImageDumpLineTable ()), "line-table", 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<char, uint32_t> > FormatWidthCollection; + FormatWidthCollection m_format_array; + }; + + CommandObjectImageList () : + CommandObject ( + "image list", + "List current executable and dependent shared library images.", + "image list [<cmd-options>]") + { + } + + virtual + ~CommandObjectImageList () + { + } + + virtual + Options * + GetOptions () + { + return &m_options; + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target *target = context->GetTarget(); + 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_idx<num_modules; ++image_idx) + { + Module *module = target->GetImages().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<num_entries; ++i) + { + if (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, "<NONE>"); + } + 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[] = +{ +{ 0, false, "arch", 'a', optional_argument, NULL, 0, "<width>", "Display the architecture when listing images."}, +{ 0, false, "uuid", 'u', no_argument, NULL, 0, NULL, "Display the UUID when listing images."}, +{ 0, false, "fullpath", 'f', optional_argument, NULL, 0, "<width>", "Display the fullpath to the image object file."}, +{ 0, false, "directory", 'd', optional_argument, NULL, 0, "<width>", "Display the directory with optional width for the image object file."}, +{ 0, false, "basename", 'b', optional_argument, NULL, 0, "<width>", "Display the basename with optional width for the image object file."}, +{ 0, false, "symfile", 's', optional_argument, NULL, 0, "<width>", "Display the fullpath to the image symbol file with optional width."}, +{ 0, false, "symfile-basename", 'S', optional_argument, NULL, 0, "<width>", "Display the basename to the image symbol file with optional width."}, +{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + + + +//---------------------------------------------------------------------- +// Lookup information in images +//---------------------------------------------------------------------- +class CommandObjectImageLookup : public CommandObject +{ +public: + + enum + { + eLookupTypeInvalid = -1, + eLookupTypeAddress = 0, + eLookupTypeSymbol, + eLookupTypeFileLine, // Line is optional + eLookupTypeFunction, + 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 '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; + } + + 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. + }; + + CommandObjectImageLookup () : + CommandObject ( + "image lookup", + "Look up information within executable and dependent shared library images.", + "image lookup [<cmd-options>] [<file1>...]") + { + } + + virtual + ~CommandObjectImageLookup () + { + } + + virtual + Options * + GetOptions () + { + return &m_options; + } + + + bool + LookupInModule (CommandContext *context, Module *module, CommandReturnObject &result, bool &syntax_error) + { + switch (m_options.m_type) + { + case eLookupTypeAddress: + if (m_options.m_addr != LLDB_INVALID_ADDRESS) + { + if (LookupAddressInModule (context, result.GetOutputStream(), module, eSymbolContextEverything, m_options.m_addr, m_options.m_offset)) + { + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + } + break; + + case eLookupTypeSymbol: + if (!m_options.m_str.empty()) + { + if (LookupSymbolInModule (context, 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 (context, + 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 (context, + result.GetOutputStream(), + module, + m_options.m_str.c_str(), + m_options.m_use_regex)) + { + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + } + break; + + default: + m_options.GenerateOptionUsage (result.GetErrorStream(), this); + syntax_error = true; + break; + } + + result.SetStatus (eReturnStatusFailed); + return false; + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target *target = context->GetTarget(); + 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; i<num_modules && syntax_error == false; ++i) + { + if (LookupInModule (context, target->GetImages().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; + const size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules); + + if (num_matching_modules > 0) + { + for (size_t i=0; i<num_matching_modules; ++i) + { + Module * image_module = matching_modules.GetModulePointerAtIndex(i); + if (image_module) + { + if (LookupInModule (context, image_module, result, syntax_error)) + { + result.GetOutputStream().EOL(); + num_successful_lookups++; + } + } + } + } + else + result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr); + } + } + + if (num_successful_lookups > 0) + result.SetStatus (eReturnStatusSuccessFinishResult); + else + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } +protected: + + CommandOptions m_options; +}; + +lldb::OptionDefinition +CommandObjectImageLookup::CommandOptions::g_option_table[] = +{ +{ 1, true, "address", 'a', required_argument, NULL, 0, "<addr>", "Lookup an address in one or more executable images."}, +{ 1, false, "offset", 'o', required_argument, NULL, 0, "<offset>", "When looking up an address subtract <offset> from any addresses before doing the lookup."}, +{ 2, true, "symbol", 's', required_argument, NULL, 0, "<name>", "Lookup a symbol by name in the symbol tables in one or more executable images."}, +{ 2, false, "regex", 'r', no_argument, NULL, 0, NULL, "The <name> argument for name lookups are regular expressions."}, +{ 3, true, "file", 'f', required_argument, NULL, 0, "<file>", "Lookup a file by fullpath or basename in one or more executable images."}, +{ 3, false, "line", 'l', required_argument, NULL, 0, "<line>", "Lookup a line number in a file (must be used in conjunction with --file)."}, +{ 3, false, "no-inlines", 'i', no_argument, NULL, 0, NULL, "Check inline line entries (must be used in conjunction with --file)."}, +{ 4, true, "function", 'n', required_argument, NULL, 0, "<name>", "Lookup a function by name in the debug symbols in one or more executable images."}, +{ 5, false, "regex", 'r', no_argument, NULL, 0, NULL, "The <name> argument for name lookups are regular expressions."}, +{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + + + + + +//---------------------------------------------------------------------- +// CommandObjectImage constructor +//---------------------------------------------------------------------- +CommandObjectImage::CommandObjectImage(CommandInterpreter *interpreter) : + CommandObjectMultiword ("image", + "Access information for one or more executable images.", + "image [dump|list] ...") +{ + LoadSubCommand (CommandObjectSP (new CommandObjectImageDump (interpreter)), "dump", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectImageList ()), "list", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectImageLookup ()), "lookup", interpreter); +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +CommandObjectImage::~CommandObjectImage() +{ +} + |