diff --git a/lldb/include/lldb/API/SBError.h b/lldb/include/lldb/API/SBError.h index 21f4e483d327..44b58ae05455 100644 --- a/lldb/include/lldb/API/SBError.h +++ b/lldb/include/lldb/API/SBError.h @@ -92,6 +92,9 @@ protected: const lldb_private::Error & operator*() const; + lldb_private::Error & + ref(); + #endif diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 049ca9025500..ed6613ad0053 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -62,6 +62,7 @@ private: friend class SBHostOS; friend class SBLineEntry; friend class SBModule; + friend class SBProcess; friend class SBSourceManager; friend class SBThread; friend class SBTarget; diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h index ad612b929238..c7c67953864e 100644 --- a/lldb/include/lldb/API/SBProcess.h +++ b/lldb/include/lldb/API/SBProcess.h @@ -103,40 +103,40 @@ public: uint32_t GetAddressByteSize() const; - SBError + lldb::SBError Destroy (); lldb::pid_t AttachByPID (lldb::pid_t pid); // DEPRECATED - // DEPRECATED: relocated to "SBProcess SBTarget::AttachToProcess (lldb::pid_t pid, SBError& error)" - SBError + // DEPRECATED: relocated to "SBProcess SBTarget::AttachToProcess (lldb::pid_t pid, lldb::SBError& error)" + lldb::SBError Attach (lldb::pid_t pid); - // DEPRECATED: relocated to "SBProcess SBTarget::AttachToProcess (const char *name, bool wait_for_launch, SBError& error)" - SBError + // DEPRECATED: relocated to "SBProcess SBTarget::AttachToProcess (const char *name, bool wait_for_launch, lldb::SBError& error)" + lldb::SBError AttachByName (const char *name, bool wait_for_launch); - SBError + lldb::SBError Continue (); - SBError + lldb::SBError Stop (); - SBError + lldb::SBError Kill (); - SBError + lldb::SBError Detach (); - SBError + lldb::SBError Signal (int signal); size_t - ReadMemory (addr_t addr, void *buf, size_t size, SBError &error); + ReadMemory (addr_t addr, void *buf, size_t size, lldb::SBError &error); size_t - WriteMemory (addr_t addr, const void *buf, size_t size, SBError &error); + WriteMemory (addr_t addr, const void *buf, size_t size, lldb::SBError &error); // Events static lldb::StateType @@ -154,6 +154,12 @@ public: bool GetDescription (lldb::SBStream &description); + uint32_t + LoadImage (lldb::SBFileSpec &image_spec, lldb::SBError &error); + + lldb::SBError + UnloadImage (uint32_t image_token); + protected: friend class SBAddress; friend class SBBreakpoint; diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index 8b1ba1c38781..aaff85e876a5 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -147,6 +147,9 @@ public: Value & GetValue(); + bool + ResolveValue (ExecutionContextScope *exe_scope, Scalar &scalar); + const char * GetLocationAsCString (ExecutionContextScope *exe_scope); diff --git a/lldb/include/lldb/Target/DynamicLoader.h b/lldb/include/lldb/Target/DynamicLoader.h index bed967859729..af1256772742 100644 --- a/lldb/include/lldb/Target/DynamicLoader.h +++ b/lldb/include/lldb/Target/DynamicLoader.h @@ -12,6 +12,7 @@ // Project includes #include "lldb/lldb-private.h" +#include "lldb/Core/Error.h" #include "lldb/Core/PluginInterface.h" namespace lldb_private { @@ -138,6 +139,23 @@ public: virtual lldb::ThreadPlanSP GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) = 0; + + //------------------------------------------------------------------ + /// Ask if it is ok to try and load or unload an shared library + /// (image). + /// + /// The dynamic loader often knows when it would be ok to try and + /// load or unload a shared library. This function call allows the + /// dynamic loader plug-ins to check any current dyld state to make + /// sure it is an ok time to load a shared library. + /// + /// @return + /// \b True if it is currently ok to try and load a shared + /// library into the process, \b false otherwise. + //------------------------------------------------------------------ + virtual Error + CanLoadImage () = 0; + protected: //------------------------------------------------------------------ // Member variables. diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 51fb04bfdd08..82a87aa4947c 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -614,6 +614,33 @@ public: virtual lldb::addr_t GetImageInfoAddress (); + //------------------------------------------------------------------ + /// Load a shared library into this process. + /// + /// Try and load a shared library into the current process. This + /// call might fail in the dynamic loader plug-in says it isn't safe + /// to try and load shared libraries at the moment. + /// + /// @param[in] image_spec + /// The image file spec that points to the shared library that + /// you want to load. + /// + /// @param[out] error + /// An error object that gets filled in with any errors that + /// might occur when trying to load the shared library. + /// + /// @return + /// A token that represents the shared library that can be + /// later used to unload the shared library. A value of + /// LLDB_INVALID_IMAGE_TOKEN will be returned if the shared + /// library can't be opened. + //------------------------------------------------------------------ + virtual uint32_t + LoadImage (const FileSpec &image_spec, Error &error); + + virtual Error + UnloadImage (uint32_t image_token); + //------------------------------------------------------------------ /// Register for process and thread notifications. /// @@ -1642,6 +1669,7 @@ protected: std::string m_exit_string; ///< A textual description of why a process exited. ThreadList m_thread_list; ///< The threads for this process. std::vector m_notifications; ///< The list of notifications that this process can deliver. + std::vector m_image_tokens; Listener &m_listener; BreakpointSiteList m_breakpoint_site_list; ///< This is the list of breakpoint locations we intend ///< to insert in the target. diff --git a/lldb/include/lldb/lldb-defines.h b/lldb/include/lldb/lldb-defines.h index e927a9d48ce8..38a689ce8067 100644 --- a/lldb/include/lldb/lldb-defines.h +++ b/lldb/include/lldb/lldb-defines.h @@ -55,6 +55,7 @@ //---------------------------------------------------------------------- #define LLDB_INVALID_ADDRESS UINT64_MAX #define LLDB_INVALID_INDEX32 UINT32_MAX +#define LLDB_INVALID_IMAGE_TOKEN UINT32_MAX #define LLDB_INVALID_REGNUM UINT32_MAX #define LLDB_INVALID_UID UINT32_MAX #define LLDB_INVALID_PROCESS_ID 0 diff --git a/lldb/source/API/SBError.cpp b/lldb/source/API/SBError.cpp index 935a869e57ba..2e01cfa8ccf9 100644 --- a/lldb/source/API/SBError.cpp +++ b/lldb/source/API/SBError.cpp @@ -199,6 +199,12 @@ SBError::get() return m_opaque_ap.get(); } +lldb_private::Error & +SBError::ref() +{ + CreateIfNeeded(); + return *m_opaque_ap; +} const lldb_private::Error & SBError::operator*() const diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp index 9ea9f754abc4..0c52b6b15d18 100644 --- a/lldb/source/API/SBProcess.cpp +++ b/lldb/source/API/SBProcess.cpp @@ -703,3 +703,24 @@ SBProcess::GetDescription (SBStream &description) return true; } + +uint32_t +SBProcess::LoadImage (lldb::SBFileSpec &sb_image_spec, lldb::SBError &sb_error) +{ + if (m_opaque_sp) + m_opaque_sp->LoadImage (*sb_image_spec, sb_error.ref()); + return LLDB_INVALID_IMAGE_TOKEN; +} + +lldb::SBError +SBProcess::UnloadImage (uint32_t image_token) +{ + lldb::SBError sb_error; + if (m_opaque_sp) + sb_error.SetError (m_opaque_sp->UnloadImage (image_token)); + else + sb_error.SetErrorString("invalid process"); + return sb_error; +} + + diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index 7f7c780978ae..2045c59d058c 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -218,21 +218,6 @@ CommandObjectExpression::EvaluateExpression return false; } - if (!m_exe_ctx.process->GetDynamicCheckers()) - { - DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions(); - - StreamString install_errors; - - if (!dynamic_checkers->Install(install_errors, m_exe_ctx)) - { - error_stream.Printf("Couldn't install dynamic checkers into the execution context: %s\n", install_errors.GetData()); - return false; - } - - m_exe_ctx.process->SetDynamicCheckers(dynamic_checkers); - } - const char *prefix = NULL; if (m_exe_ctx.target) diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp index 8c4ffdd96bb6..88fdca3086bf 100644 --- a/lldb/source/Commands/CommandObjectProcess.cpp +++ b/lldb/source/Commands/CommandObjectProcess.cpp @@ -852,6 +852,128 @@ public: } }; +//------------------------------------------------------------------------- +// CommandObjectProcessLoad +//------------------------------------------------------------------------- + +class CommandObjectProcessLoad : public CommandObject +{ +public: + + CommandObjectProcessLoad (CommandInterpreter &interpreter) : + CommandObject (interpreter, + "process load", + "Load a shared library into the current process.", + "process load [ ...]", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) + { + } + + ~CommandObjectProcessLoad () + { + } + + bool + Execute (Args& command, + CommandReturnObject &result) + { + Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + if (process == NULL) + { + result.AppendError ("must have a valid process in order to load a shared library"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const uint32_t argc = command.GetArgumentCount(); + + for (uint32_t i=0; iLoadImage(image_spec, error); + if (image_token != LLDB_INVALID_IMAGE_TOKEN) + { + result.AppendMessageWithFormat ("Loading \"%s\"...ok\nImage %u loaded.\n", image_path, image_token); + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendErrorWithFormat ("failed to load '%s': %s", image_path, error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + return result.Succeeded(); + } +}; + + +//------------------------------------------------------------------------- +// CommandObjectProcessUnload +//------------------------------------------------------------------------- + +class CommandObjectProcessUnload : public CommandObject +{ +public: + + CommandObjectProcessUnload (CommandInterpreter &interpreter) : + CommandObject (interpreter, + "process unload", + "Unload a shared library from the current process using the index returned by a previous call to \"process load\".", + "process unload ", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) + { + } + + ~CommandObjectProcessUnload () + { + } + + bool + Execute (Args& command, + CommandReturnObject &result) + { + Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + if (process == NULL) + { + result.AppendError ("must have a valid process in order to load a shared library"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const uint32_t argc = command.GetArgumentCount(); + + for (uint32_t i=0; iUnloadImage(image_token)); + if (error.Success()) + { + result.AppendMessageWithFormat ("Unloading shared library with index %u...ok\n", image_token); + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendErrorWithFormat ("failed to unload image: %s", error.AsCString()); + result.SetStatus (eReturnStatusFailed); + break; + } + } + } + return result.Succeeded(); + } +}; + //------------------------------------------------------------------------- // CommandObjectProcessSignal //------------------------------------------------------------------------- @@ -1450,6 +1572,8 @@ CommandObjectMultiwordProcess::CommandObjectMultiwordProcess (CommandInterpreter LoadSubCommand ("launch", CommandObjectSP (new CommandObjectProcessLaunch (interpreter))); LoadSubCommand ("continue", CommandObjectSP (new CommandObjectProcessContinue (interpreter))); LoadSubCommand ("detach", CommandObjectSP (new CommandObjectProcessDetach (interpreter))); + LoadSubCommand ("load", CommandObjectSP (new CommandObjectProcessLoad (interpreter))); + LoadSubCommand ("unload", CommandObjectSP (new CommandObjectProcessUnload (interpreter))); LoadSubCommand ("signal", CommandObjectSP (new CommandObjectProcessSignal (interpreter))); LoadSubCommand ("handle", CommandObjectSP (new CommandObjectProcessHandle (interpreter))); LoadSubCommand ("status", CommandObjectSP (new CommandObjectProcessStatus (interpreter))); diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 2efd4432d58a..a3da90d9c3aa 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -221,6 +221,15 @@ ValueObject::GetValue() const return m_value; } +bool +ValueObject::ResolveValue (ExecutionContextScope *exe_scope, Scalar &scalar) +{ + ExecutionContext exe_ctx; + exe_scope->CalculateExecutionContext(exe_ctx); + scalar = m_value.ResolveValue(&exe_ctx, GetClangAST ()); + return scalar.IsValid(); +} + bool ValueObject::GetValueIsValid () const { diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index dc93d8e69717..5181c98c9aa3 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -30,6 +30,7 @@ #include "lldb/Host/Host.h" #include "lldb/Symbol/VariableList.h" #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" @@ -437,6 +438,22 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx, { Error error; lldb::ValueObjectSP result_valobj_sp; + + if (exe_ctx.process == NULL) + return result_valobj_sp; + + if (!exe_ctx.process->GetDynamicCheckers()) + { + DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions(); + + StreamString install_errors; + + if (!dynamic_checkers->Install(install_errors, exe_ctx)) + return result_valobj_sp; + + exe_ctx.process->SetDynamicCheckers(dynamic_checkers); + } + ClangUserExpression user_expression (expr_cstr, expr_prefix); StreamString error_stream; diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp index fa46c77553aa..bdfc47c48ff7 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp @@ -1167,6 +1167,26 @@ DynamicLoaderMacOSXDYLD::GetStepThroughTrampolinePlan (Thread &thread, bool stop return thread_plan_sp; } +Error +DynamicLoaderMacOSXDYLD::CanLoadImage () +{ + Error error; + // In order for us to tell if we can load a shared library we verify that + // the dylib_info_addr isn't zero (which means no shared libraries have + // been set yet, or dyld is currently mucking with the shared library list). + if (ReadAllImageInfosStructure ()) + { + // TODO: also check the _dyld_global_lock_held variable in libSystem.B.dylib? + // TODO: check the malloc lock? + // TODO: check the objective C lock? + if (m_dyld_all_image_infos.dylib_info_addr != 0) + return error; // Success + } + + error.SetErrorString("unsafe to load or unload shared libraries"); + return error; +} + void DynamicLoaderMacOSXDYLD::Initialize() { diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h index 8f22dbdcb630..34ea8a46781f 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h @@ -78,6 +78,8 @@ public: GetStepThroughTrampolinePlan (lldb_private::Thread &thread, bool stop_others); + virtual lldb_private::Error + CanLoadImage (); //------------------------------------------------------------------ // PluginInterface protocol diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index d71626790bff..fa7ac71c89e0 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -21,6 +21,7 @@ #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Host/Host.h" #include "lldb/Target/ABI.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/CPPLanguageRuntime.h" #include "lldb/Target/ObjCLanguageRuntime.h" @@ -471,6 +472,141 @@ Process::GetImageInfoAddress() return LLDB_INVALID_ADDRESS; } +//---------------------------------------------------------------------- +// LoadImage +// +// This function provides a default implementation that works for most +// unix variants. Any Process subclasses that need to do shared library +// loading differently should override LoadImage and UnloadImage and +// do what is needed. +//---------------------------------------------------------------------- +uint32_t +Process::LoadImage (const FileSpec &image_spec, Error &error) +{ + DynamicLoader *loader = GetDynamicLoader(); + if (loader) + { + error = loader->CanLoadImage(); + if (error.Fail()) + return LLDB_INVALID_IMAGE_TOKEN; + } + + if (error.Success()) + { + ThreadSP thread_sp(GetThreadList ().GetSelectedThread()); + if (thread_sp == NULL) + thread_sp = GetThreadList ().GetThreadAtIndex(0, true); + + if (thread_sp) + { + StackFrameSP frame_sp (thread_sp->GetStackFrameAtIndex (0)); + + if (frame_sp) + { + ExecutionContext exe_ctx; + frame_sp->CalculateExecutionContext (exe_ctx); + + StreamString expr; + char path[PATH_MAX]; + image_spec.GetPath(path, sizeof(path)); + expr.Printf("dlopen (\"%s\", 2)", path); + const char *prefix = "extern \"C\" void* dlopen (const char *path, int mode);\n"; + lldb::ValueObjectSP result_valobj_sp (ClangUserExpression::Evaluate (exe_ctx, expr.GetData(), prefix)); + if (result_valobj_sp->GetError().Success()) + { + Scalar scalar; + if (result_valobj_sp->ResolveValue (frame_sp.get(), scalar)) + { + addr_t image_ptr = scalar.ULongLong(LLDB_INVALID_ADDRESS); + if (image_ptr != 0 && image_ptr != LLDB_INVALID_ADDRESS) + { + uint32_t image_token = m_image_tokens.size(); + m_image_tokens.push_back (image_ptr); + return image_token; + } + } + } + } + } + } + return LLDB_INVALID_IMAGE_TOKEN; +} + +//---------------------------------------------------------------------- +// UnloadImage +// +// This function provides a default implementation that works for most +// unix variants. Any Process subclasses that need to do shared library +// loading differently should override LoadImage and UnloadImage and +// do what is needed. +//---------------------------------------------------------------------- +Error +Process::UnloadImage (uint32_t image_token) +{ + Error error; + if (image_token < m_image_tokens.size()) + { + const addr_t image_addr = m_image_tokens[image_token]; + if (image_addr == LLDB_INVALID_ADDRESS) + { + error.SetErrorString("image already unloaded"); + } + else + { + DynamicLoader *loader = GetDynamicLoader(); + if (loader) + error = loader->CanLoadImage(); + + if (error.Success()) + { + ThreadSP thread_sp(GetThreadList ().GetSelectedThread()); + if (thread_sp == NULL) + thread_sp = GetThreadList ().GetThreadAtIndex(0, true); + + if (thread_sp) + { + StackFrameSP frame_sp (thread_sp->GetStackFrameAtIndex (0)); + + if (frame_sp) + { + ExecutionContext exe_ctx; + frame_sp->CalculateExecutionContext (exe_ctx); + + StreamString expr; + expr.Printf("dlclose ((void *)0x%llx)", image_addr); + const char *prefix = "extern \"C\" int dlclose(void* handle);\n"; + lldb::ValueObjectSP result_valobj_sp (ClangUserExpression::Evaluate (exe_ctx, expr.GetData(), prefix)); + if (result_valobj_sp->GetError().Success()) + { + Scalar scalar; + if (result_valobj_sp->ResolveValue (frame_sp.get(), scalar)) + { + if (scalar.UInt(1)) + { + error.SetErrorStringWithFormat("expression failed: \"%s\"", expr.GetData()); + } + else + { + m_image_tokens[image_token] = LLDB_INVALID_ADDRESS; + } + } + } + else + { + error = result_valobj_sp->GetError(); + } + } + } + } + } + } + else + { + error.SetErrorString("invalid image token"); + } + return error; +} + DynamicLoader * Process::GetDynamicLoader() {