Index: include/lldb/Core/Module.h =================================================================== --- include/lldb/Core/Module.h +++ include/lldb/Core/Module.h @@ -962,6 +962,20 @@ bool RemapSourceFile(llvm::StringRef path, std::string &new_path) const; bool RemapSourceFile(const char *, std::string &) const = delete; + //------------------------------------------------------------------ + /// Loads this module to memory. + /// + /// Loads the bits needed to create an executable image to the memory. + /// It is useful with bare-metal targets where target does not have the + /// ability to start a process itself. + /// + /// @param[in] target + /// Target where to load the module. + /// + /// @return + //------------------------------------------------------------------ + Error LoadInMemory(Target &target); + //---------------------------------------------------------------------- /// @class LookupInfo Module.h "lldb/Core/Module.h" /// @brief A class that encapsulates name lookup information. Index: include/lldb/Symbol/ObjectFile.h =================================================================== --- include/lldb/Symbol/ObjectFile.h +++ include/lldb/Symbol/ObjectFile.h @@ -774,6 +774,20 @@ llvm::StringRef name, lldb::SymbolType symbol_type_hint = lldb::eSymbolTypeUndefined); + //------------------------------------------------------------------ + /// Loads this objfile to memory. + /// + /// Loads the bits needed to create an executable image to the memory. + /// It is useful with bare-metal targets where target does not have the + /// ability to start a process itself. + /// + /// @param[in] target + /// Target where to load. + /// + /// @return + //------------------------------------------------------------------ + virtual Error LoadInMemory(Target &target); + protected: //------------------------------------------------------------------ // Member variables. Index: source/Commands/CommandObjectTarget.cpp =================================================================== --- source/Commands/CommandObjectTarget.cpp +++ source/Commands/CommandObjectTarget.cpp @@ -2567,6 +2567,10 @@ m_option_group(), m_file_option(LLDB_OPT_SET_1, false, "file", 'f', 0, eArgTypeName, "Fullpath or basename for module to load.", ""), + m_load_option(LLDB_OPT_SET_1, false, "load", 'l', + "Write file contents to the memory and set PC to its" + "entry address.", + false, true), m_slide_option(LLDB_OPT_SET_1, false, "slide", 's', 0, eArgTypeOffset, "Set the load address for all sections to be the " "virtual address in the file plus the offset.", @@ -2574,6 +2578,7 @@ m_option_group.Append(&m_uuid_option_group, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append(&m_file_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + m_option_group.Append(&m_load_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append(&m_slide_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Finalize(); } @@ -2585,6 +2590,7 @@ protected: bool DoExecute(Args &args, CommandReturnObject &result) override { Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + const bool load = m_load_option.GetOptionValue().GetCurrentValue(); if (target == nullptr) { result.AppendError("invalid target, create a debug target using the " "'target create' command"); @@ -2594,6 +2600,21 @@ const size_t argc = args.GetArgumentCount(); ModuleSpec module_spec; bool search_using_module_spec = false; + + // Allow "load" option to work without --file or --uuid + // option. + if (load) { + if (!m_file_option.GetOptionValue().OptionWasSet() && + !m_uuid_option_group.GetOptionValue().OptionWasSet()) { + ModuleList &module_list = target->GetImages(); + if (module_list.GetSize() == 1) { + search_using_module_spec = true; + module_spec.GetFileSpec() = + module_list.GetModuleAtIndex(0)->GetFileSpec(); + } + } + } + if (m_file_option.GetOptionValue().OptionWasSet()) { search_using_module_spec = true; const char *arg_cstr = m_file_option.GetOptionValue().GetCurrentValue(); @@ -2721,6 +2742,13 @@ if (process) process->Flush(); } + if (load) { + Error error = module->LoadInMemory(*target); + if (error.Fail()) { + result.AppendError(error.AsCString()); + return false; + } + } } else { module->GetFileSpec().GetPath(path, sizeof(path)); result.AppendErrorWithFormat( @@ -2783,6 +2811,7 @@ OptionGroupOptions m_option_group; OptionGroupUUID m_uuid_option_group; OptionGroupString m_file_option; + OptionGroupBoolean m_load_option; OptionGroupUInt64 m_slide_option; }; Index: source/Core/Module.cpp =================================================================== --- source/Core/Module.cpp +++ source/Core/Module.cpp @@ -1664,3 +1664,7 @@ return false; } + +Error Module::LoadInMemory(Target &target) { + return m_objfile_sp->LoadInMemory(target); +} Index: source/Symbol/ObjectFile.cpp =================================================================== --- source/Symbol/ObjectFile.cpp +++ source/Symbol/ObjectFile.cpp @@ -20,6 +20,9 @@ #include "lldb/Core/Timer.h" #include "lldb/Symbol/ObjectContainer.h" #include "lldb/Symbol/SymbolFile.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Process.h" #include "lldb/lldb-private.h" @@ -648,3 +651,31 @@ file_name.GetCString()); return ConstString(ss.GetString()); } + +Error ObjectFile::LoadInMemory(Target &target) { + Error error; + ProcessSP process = target.CalculateProcess(); + if (!process) + return Error("No Process"); + + SectionList *section_list = GetSectionList(); + if (!section_list) + return Error("No section in object file"); + size_t section_count = section_list->GetNumSections(0); + for (size_t i = 0; i < section_count; ++i) { + SectionSP section_sp = section_list->GetSectionAtIndex(i); + addr_t addr = target.GetSectionLoadList().GetSectionLoadAddress(section_sp); + if (addr != LLDB_INVALID_ADDRESS) { + DataExtractor section_data; + // We can skip sections like bss + if (section_sp->GetFileSize() == 0) + continue; + section_sp->GetSectionData(section_data); + lldb::offset_t written = process->WriteMemory( + addr, section_data.GetDataStart(), section_data.GetByteSize(), error); + if (written != section_data.GetByteSize()) + return error; + } + } + return error; +}