diff --git a/lldb/include/lldb/Interpreter/OptionValue.h b/lldb/include/lldb/Interpreter/OptionValue.h index 99f52b0411b9c..277a5c9d30f05 100644 --- a/lldb/include/lldb/Interpreter/OptionValue.h +++ b/lldb/include/lldb/Interpreter/OptionValue.h @@ -311,7 +311,6 @@ class OptionValue { lldb::OptionValueSP GetParent() const { return m_parent_wp.lock(); } void SetValueChangedCallback(std::function callback) { - assert(!m_callback); m_callback = std::move(callback); } diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 54c1fb5840c9d..faa77a2ac5957 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -158,8 +158,8 @@ class TargetProperties : public Properties { bool GetEnableNotifyAboutFixIts() const; - bool GetEnableSaveObjects() const; - + FileSpec GetSaveJITObjectsDir() const; + bool GetEnableSyntheticValue() const; uint32_t GetMaxZeroPaddingInFloatFormat() const; @@ -248,6 +248,9 @@ class TargetProperties : public Properties { void DisableASLRValueChangedCallback(); void InheritTCCValueChangedCallback(); void DisableSTDIOValueChangedCallback(); + + // Settings checker for target.jit-save-objects-dir: + void CheckJITObjectsDir(); Environment ComputeEnvironment() const; diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index 92c91deb46e97..91b92f1ba3003 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -21,6 +21,7 @@ #include "lldb/Core/Module.h" #include "lldb/Core/Section.h" #include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/SymbolFile.h" @@ -306,27 +307,37 @@ void IRExecutionUnit::GetRunnableInfo(Status &error, lldb::addr_t &func_addr, class ObjectDumper : public llvm::ObjectCache { public: + ObjectDumper(FileSpec output_dir) : m_out_dir(output_dir) {} void notifyObjectCompiled(const llvm::Module *module, llvm::MemoryBufferRef object) override { int fd = 0; llvm::SmallVector result_path; std::string object_name_model = "jit-object-" + module->getModuleIdentifier() + "-%%%.o"; - (void)llvm::sys::fs::createUniqueFile(object_name_model, fd, result_path); - llvm::raw_fd_ostream fds(fd, true); - fds.write(object.getBufferStart(), object.getBufferSize()); + FileSpec model_spec + = m_out_dir.CopyByAppendingPathComponent(object_name_model); + std::string model_path = model_spec.GetPath(); + + std::error_code result + = llvm::sys::fs::createUniqueFile(model_path, fd, result_path); + if (!result) { + llvm::raw_fd_ostream fds(fd, true); + fds.write(object.getBufferStart(), object.getBufferSize()); + } } - std::unique_ptr - getObject(const llvm::Module *module) override { + getObject(const llvm::Module *module) override { // Return nothing - we're just abusing the object-cache mechanism to dump // objects. return nullptr; - } + } + private: + FileSpec m_out_dir; }; - if (process_sp->GetTarget().GetEnableSaveObjects()) { - m_object_cache_up = std::make_unique(); + FileSpec save_objects_dir = process_sp->GetTarget().GetSaveJITObjectsDir(); + if (save_objects_dir) { + m_object_cache_up = std::make_unique(save_objects_dir); m_execution_engine_up->setObjectCache(m_object_cache_up.get()); } diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 14b5ecfacf384..6e8cc1df89398 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -3814,6 +3814,8 @@ TargetProperties::TargetProperties(Target *target) m_collection_sp->SetValueChangedCallback( ePropertyDisableSTDIO, [this] { DisableSTDIOValueChangedCallback(); }); + m_collection_sp->SetValueChangedCallback( + ePropertySaveObjectsDir, [this] { CheckJITObjectsDir(); }); m_experimental_properties_up = std::make_unique(); m_collection_sp->AppendProperty( @@ -3835,6 +3837,8 @@ TargetProperties::TargetProperties(Target *target) m_collection_sp->AppendProperty( ConstString("process"), ConstString("Settings specific to processes."), true, Process::GetGlobalProperties().GetValueProperties()); + m_collection_sp->SetValueChangedCallback( + ePropertySaveObjectsDir, [this] { CheckJITObjectsDir(); }); } } @@ -4164,10 +4168,41 @@ bool TargetProperties::GetEnableNotifyAboutFixIts() const { nullptr, idx, g_target_properties[idx].default_uint_value != 0); } -bool TargetProperties::GetEnableSaveObjects() const { - const uint32_t idx = ePropertySaveObjects; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); +FileSpec TargetProperties::GetSaveJITObjectsDir() const { + const uint32_t idx = ePropertySaveObjectsDir; + return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); +} + +void TargetProperties::CheckJITObjectsDir() { + const uint32_t idx = ePropertySaveObjectsDir; + FileSpec new_dir = GetSaveJITObjectsDir(); + const FileSystem &instance = FileSystem::Instance(); + bool exists = instance.Exists(new_dir); + bool is_directory = instance.IsDirectory(new_dir); + std::string path = new_dir.GetPath(true); + bool writable = llvm::sys::fs::can_write(path); + if (exists && is_directory && writable) + return; + m_collection_sp->GetPropertyAtIndex(nullptr, true, idx)->GetValue() + ->Clear(); + StreamSP error_strm_sp; + if (m_target) { + // FIXME: How can I warn the user when setting this on the Debugger? + error_strm_sp = m_target->GetDebugger().GetAsyncErrorStream(); + } else if (Debugger::GetNumDebuggers() == 1) { + error_strm_sp = Debugger::GetDebuggerAtIndex(0)->GetAsyncErrorStream(); + } + if (error_strm_sp) { + error_strm_sp->Format("JIT object dir '{0}' ", path); + if (!exists) + error_strm_sp->PutCString("does not exist."); + else if (!is_directory) + error_strm_sp->PutCString("is not a directory."); + else if (!writable) + error_strm_sp->PutCString("is not writable."); + error_strm_sp->EOL(); + error_strm_sp->Flush(); + } } bool TargetProperties::GetEnableSyntheticValue() const { diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td index 063ba0a6c25af..0f46b4ca854cc 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -63,9 +63,9 @@ let Definition = "target" in { def NotifyAboutFixIts: Property<"notify-about-fixits", "Boolean">, DefaultTrue, Desc<"Print the fixed expression text.">; - def SaveObjects: Property<"save-jit-objects", "Boolean">, - DefaultFalse, - Desc<"Save intermediate object files generated by the LLVM JIT">; + def SaveObjectsDir: Property<"save-jit-objects-dir", "FileSpec">, + DefaultStringValue<"">, + Desc<"If specified, the directory to save intermediate object files generated by the LLVM JIT">; def MaxZeroPaddingInFloatFormat: Property<"max-zero-padding-in-float-format", "UInt64">, DefaultUnsignedValue<6>, Desc<"The maximum number of zeroes to insert when displaying a very small float before falling back to scientific notation.">; diff --git a/lldb/test/API/commands/expression/save_jit_objects/TestSaveJITObjects.py b/lldb/test/API/commands/expression/save_jit_objects/TestSaveJITObjects.py index b7124e1587d23..381527ca95963 100644 --- a/lldb/test/API/commands/expression/save_jit_objects/TestSaveJITObjects.py +++ b/lldb/test/API/commands/expression/save_jit_objects/TestSaveJITObjects.py @@ -38,14 +38,14 @@ def test_save_jit_objects(self): self.cleanJITFiles() frame.EvaluateExpression("(void*)malloc(0x1)") self.assertEquals(self.countJITFiles(), 0, - "No files emitted with save-jit-objects=false") - - self.runCmd("settings set target.save-jit-objects true") + "No files emitted with save-jit-objects-dir empty") + + self.runCmd("settings set target.save-jit-objects-dir {0}".format(self.getBuildDir())) frame.EvaluateExpression("(void*)malloc(0x1)") jit_files_count = self.countJITFiles() self.cleanJITFiles() self.assertNotEqual(jit_files_count, 0, - "At least one file emitted with save-jit-objects=true") + "At least one file emitted with save-jit-objects-dir set to the build dir") process.Kill() os.chdir(self.getSourceDir())