jingham created this revision. jingham added reviewers: clayborg, labath, JDevlieghere. Herald added a project: All. jingham requested review of this revision. Herald added a project: LLDB. Herald added a subscriber: lldb-commits.
One of the diagnostic outputs for the expression parser is the jit objects. The way you used to produce these was to set "target.save-jit-objects" to true and the files would get dumped into the CWD. That's not going to work if the CWD is not writeable (which for GUI apps on macOS is almost always true). It's also a little annoying to dump them unconditionally in the CWD rather than letting the user specify a directory. So this patch changes `target.save-jit-objects` to `target.save-jit-objects-dir`. If this is empty we do nothing and if it has a path we put the files there. That part seems straightforward, but I also try to validate that the path you provided is good. The checking part again is easy, but there are three tricky bits, one of which I resolved and two of which I punted. 1. If you want to add a ValueChanged callback to a setting, you need to put the callback into the global properties so you can check when the setting is done before you have a target. But you also need to insert it into the copy that the target gets, however the callback captures the TargetProperties object it is going to inspect, that's how it knows what to work on, so the callback has to be different. That's actually fine, except that we have an assert if you try to overwrite a callback. That assert has been there forever, but I don't know why, and in this case it is something you need to do. So I removed the assert. 2. When we find an incorrect save directory I would like to inform the user that something is wrong. That works for the Target's local copy, because I can get the Debugger and use its ErrorOutput. But the Global copy of the TargetProperty objects doesn't have links back to anything that can be informed. I don't have a good way to solve this currently. You can't use the Debugger that caused the creation of the global properties since it might no longer be around. I could add the hack of "If there's only one debugger, tell it" which would work for command line lldb. I didn't do that yet in this patch but if there aren't any better ideas I am willing to add that. It seem unfriendly to spray it across all the debuggers... 3. A better way to fix this would probably be to allow the ValueChanged callbacks to report an error back up to whoever it trying to change the value, which in the end would result in a "settings set" error. But that's way more infrastructure than I can invest in right now. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D121036 Files: lldb/include/lldb/Interpreter/OptionValue.h lldb/include/lldb/Target/Target.h lldb/source/Expression/IRExecutionUnit.cpp lldb/source/Target/Target.cpp lldb/source/Target/TargetProperties.td lldb/test/API/commands/expression/save_jit_objects/TestSaveJITObjects.py
Index: lldb/test/API/commands/expression/save_jit_objects/TestSaveJITObjects.py =================================================================== --- lldb/test/API/commands/expression/save_jit_objects/TestSaveJITObjects.py +++ lldb/test/API/commands/expression/save_jit_objects/TestSaveJITObjects.py @@ -38,14 +38,14 @@ 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()) Index: lldb/source/Target/TargetProperties.td =================================================================== --- lldb/source/Target/TargetProperties.td +++ lldb/source/Target/TargetProperties.td @@ -63,9 +63,9 @@ 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.">; Index: lldb/source/Target/Target.cpp =================================================================== --- lldb/source/Target/Target.cpp +++ lldb/source/Target/Target.cpp @@ -3814,6 +3814,8 @@ m_collection_sp->SetValueChangedCallback( ePropertyDisableSTDIO, [this] { DisableSTDIOValueChangedCallback(); }); + m_collection_sp->SetValueChangedCallback( + ePropertySaveObjectsDir, [this] { CheckJITObjectsDir(); }); m_experimental_properties_up = std::make_unique<TargetExperimentalProperties>(); m_collection_sp->AppendProperty( @@ -3835,6 +3837,8 @@ m_collection_sp->AppendProperty( ConstString("process"), ConstString("Settings specific to processes."), true, Process::GetGlobalProperties().GetValueProperties()); + m_collection_sp->SetValueChangedCallback( + ePropertySaveObjectsDir, [this] { CheckJITObjectsDir(); }); } } @@ -4164,12 +4168,40 @@ 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) { + m_collection_sp->GetPropertyAtIndex(nullptr, true, idx)->GetValue() + ->Clear(); + if (m_target) { + // FIXME: How can I warn the user when setting this on the Debugger? + Debugger &debugger = m_target->GetDebugger(); + StreamSP error_strm = debugger.GetAsyncErrorStream(); + error_strm->Format("JIT object dir '{0}' ", path); + if (!exists) + error_strm->PutCString("does not exist."); + else if (!is_directory) + error_strm->PutCString("is not a directory."); + else if (!writable) + error_strm->PutCString("is not writable."); + error_strm->EOL(); + error_strm->Flush(); + } + } +} + + bool TargetProperties::GetEnableSyntheticValue() const { const uint32_t idx = ePropertyEnableSynthetic; return m_collection_sp->GetPropertyAtIndexAsBoolean( Index: lldb/source/Expression/IRExecutionUnit.cpp =================================================================== --- lldb/source/Expression/IRExecutionUnit.cpp +++ 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 @@ 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<char, 256> 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<llvm::MemoryBuffer> - 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<ObjectDumper>(); + FileSpec save_objects_dir = process_sp->GetTarget().GetSaveJITObjectsDir(); + if (save_objects_dir) { + m_object_cache_up = std::make_unique<ObjectDumper>(save_objects_dir); m_execution_engine_up->setObjectCache(m_object_cache_up.get()); } Index: lldb/include/lldb/Target/Target.h =================================================================== --- lldb/include/lldb/Target/Target.h +++ lldb/include/lldb/Target/Target.h @@ -158,8 +158,8 @@ bool GetEnableNotifyAboutFixIts() const; - bool GetEnableSaveObjects() const; - + FileSpec GetSaveJITObjectsDir() const; + bool GetEnableSyntheticValue() const; uint32_t GetMaxZeroPaddingInFloatFormat() const; @@ -248,6 +248,9 @@ void DisableASLRValueChangedCallback(); void InheritTCCValueChangedCallback(); void DisableSTDIOValueChangedCallback(); + + // Settings checker for target.jit-save-objects-dir: + void CheckJITObjectsDir(); Environment ComputeEnvironment() const; Index: lldb/include/lldb/Interpreter/OptionValue.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValue.h +++ lldb/include/lldb/Interpreter/OptionValue.h @@ -311,7 +311,6 @@ lldb::OptionValueSP GetParent() const { return m_parent_wp.lock(); } void SetValueChangedCallback(std::function<void()> callback) { - assert(!m_callback); m_callback = std::move(callback); }
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits