lawrence_danna updated this revision to Diff 224527. lawrence_danna marked 7 inline comments as done. lawrence_danna added a comment.
review fixes Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D68737/new/ https://reviews.llvm.org/D68737 Files: lldb/include/lldb/API/SBFile.h lldb/include/lldb/Host/File.h lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py lldb/scripts/Python/python-typemaps.swig lldb/scripts/interface/SBFile.i lldb/source/API/SBFile.cpp lldb/source/Host/common/File.cpp lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
Index: lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h +++ lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -638,7 +638,7 @@ void Reset(PyRefType type, PyObject *py_obj) override; ArgInfo GetNumArguments() const; - + // If the callable is a Py_Class, then find the number of arguments // of the __init__ method. ArgInfo GetNumInitArguments() const; @@ -658,7 +658,6 @@ class PythonFile : public PythonObject { public: PythonFile(); - PythonFile(File &file, const char *mode); PythonFile(PyRefType type, PyObject *o); ~PythonFile() override; @@ -668,7 +667,21 @@ using PythonObject::Reset; void Reset(PyRefType type, PyObject *py_obj) override; - void Reset(File &file, const char *mode); + + static llvm::Expected<PythonFile> FromFile(File &file, + const char *mode = nullptr); + + // FIXME delete this after FILE* typemaps are deleted + // and ScriptInterpreterPython is fixed + PythonFile(File &file, const char *mode = nullptr) { + auto f = FromFile(file, mode); + if (f) + *this = std::move(f.get()); + else { + Reset(); + llvm::consumeError(f.takeError()); + } + } lldb::FileUP GetUnderlyingFile() const; Index: lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -22,6 +22,7 @@ #include "lldb/Utility/Stream.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Errno.h" @@ -1012,8 +1013,6 @@ PythonFile::PythonFile() : PythonObject() {} -PythonFile::PythonFile(File &file, const char *mode) { Reset(file, mode); } - PythonFile::PythonFile(PyRefType type, PyObject *o) { Reset(type, o); } PythonFile::~PythonFile() {} @@ -1063,25 +1062,6 @@ PythonObject::Reset(PyRefType::Borrowed, result.get()); } -void PythonFile::Reset(File &file, const char *mode) { - if (!file.IsValid()) { - Reset(); - return; - } - - char *cmode = const_cast<char *>(mode); -#if PY_MAJOR_VERSION >= 3 - Reset(PyRefType::Owned, PyFile_FromFd(file.GetDescriptor(), nullptr, cmode, - -1, nullptr, "ignore", nullptr, 0)); -#else - // Read through the Python source, doesn't seem to modify these strings - Reset(PyRefType::Owned, - PyFile_FromFile(file.GetStream(), const_cast<char *>(""), cmode, - nullptr)); -#endif -} - - FileUP PythonFile::GetUnderlyingFile() const { if (!IsValid()) return nullptr; @@ -1236,6 +1216,13 @@ return base_error; }; + PyObject *GetPythonObject() const { + assert(m_py_obj.IsValid()); + return m_py_obj.get(); + } + + static bool classof(const File *file) = delete; + protected: PythonFile m_py_obj; bool m_borrowed; @@ -1250,7 +1237,14 @@ SimplePythonFile(const PythonFile &file, bool borrowed, int fd, File::OpenOptions options) : OwnedPythonFile(file, borrowed, fd, options, false) {} + + static char ID; + bool isA(const void *classID) const override { + return classID == &ID || NativeFile::isA(classID); + } + static bool classof(const File *file) { return file->isA(&ID); } }; +char SimplePythonFile::ID = 0; } // namespace #if PY_MAJOR_VERSION >= 3 @@ -1319,7 +1313,18 @@ return Status(); } + Expected<File::OpenOptions> GetOptions() const override { + GIL takeGIL; + return GetOptionsForPyObject(m_py_obj); + } + + static char ID; + bool isA(const void *classID) const override { + return classID == &ID || File::isA(classID); + } + static bool classof(const File *file) { return file->isA(&ID); } }; +char PythonIOFile::ID = 0; } // namespace namespace { @@ -1540,4 +1545,40 @@ #endif } +Expected<PythonFile> PythonFile::FromFile(File &file, const char *mode) { + if (!file.IsValid()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "invalid file"); + + auto *simple = llvm::dyn_cast<SimplePythonFile>(&file); + if (simple) + return Retain<PythonFile>(simple->GetPythonObject()); + auto *pythonio = llvm::dyn_cast<PythonIOFile>(&file); + if (pythonio) + return Retain<PythonFile>(pythonio->GetPythonObject()); + + if (!mode) { + auto m = file.GetOpenMode(); + if (!m) + return m.takeError(); + mode = m.get(); + } + + PyObject *file_obj; +#if PY_MAJOR_VERSION >= 3 + file_obj = PyFile_FromFd(file.GetDescriptor(), nullptr, mode, -1, nullptr, + "ignore", nullptr, 0); +#else + // Read through the Python source, doesn't seem to modify these strings + char *cmode = const_cast<char *>(mode); + file_obj = + PyFile_FromFile(file.GetStream(), const_cast<char *>(""), cmode, nullptr); +#endif + + if (!file_obj) + return exception(); + + return Take<PythonFile>(file_obj); +} + #endif Index: lldb/source/Host/common/File.cpp =================================================================== --- lldb/source/Host/common/File.cpp +++ lldb/source/Host/common/File.cpp @@ -39,7 +39,8 @@ using namespace lldb_private; using llvm::Expected; -static Expected<const char *> GetStreamOpenModeFromOptions(uint32_t options) { +Expected<const char *> +File::GetStreamOpenModeFromOptions(File::OpenOptions options) { if (options & File::eOpenOptionAppend) { if (options & File::eOpenOptionRead) { if (options & File::eOpenOptionCanCreateNewOnly) @@ -226,6 +227,12 @@ return result; } +Expected<File::OpenOptions> File::GetOptions() const { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "GetOptions() not implemented for this File class"); +} + uint32_t File::GetPermissions(Status &error) const { int fd = GetDescriptor(); if (!DescriptorIsValid(fd)) { @@ -241,6 +248,8 @@ return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); } +Expected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; } + int NativeFile::GetDescriptor() const { if (DescriptorIsValid()) return m_descriptor; @@ -758,3 +767,6 @@ return mode; } + +char File::ID = 0; +char NativeFile::ID = 0; Index: lldb/source/API/SBFile.cpp =================================================================== --- lldb/source/API/SBFile.cpp +++ lldb/source/API/SBFile.cpp @@ -108,6 +108,11 @@ return LLDB_RECORD_RESULT(!IsValid()); } +FileSP SBFile::GetFile() const { + LLDB_RECORD_METHOD_CONST_NO_ARGS(FileSP, SBFile, GetFile); + return m_opaque_sp; +} + namespace lldb_private { namespace repro { @@ -117,6 +122,7 @@ LLDB_REGISTER_METHOD_CONST(bool, SBFile, IsValid, ()); LLDB_REGISTER_METHOD_CONST(bool, SBFile, operator bool,()); LLDB_REGISTER_METHOD_CONST(bool, SBFile, operator!,()); + LLDB_REGISTER_METHOD_CONST(FileSP, SBFile, GetFile, ()); LLDB_REGISTER_METHOD(lldb::SBError, SBFile, Close, ()); } } // namespace repro Index: lldb/scripts/interface/SBFile.i =================================================================== --- lldb/scripts/interface/SBFile.i +++ lldb/scripts/interface/SBFile.i @@ -77,6 +77,23 @@ operator bool() const; SBError Close(); + + %feature("docstring", " + Convert this SBFile into a python io.IOBase file object. + + If the SBFile is itself a wrapper around a python file object, + this will return that original object. + + The file returned from here should be considered borrowed, + in the sense that you may read and write to it, and flush it, + etc, but you should not close it. If you want to close the + SBFile, call SBFile.Close(). + + If there is no underlying python file to unwrap, GetFile will + use the file descirptor, if availble to create a new python + file object using `open(fd, mode=..., closefd=False)` + "); + FileSP GetFile(); }; } // namespace lldb Index: lldb/scripts/Python/python-typemaps.swig =================================================================== --- lldb/scripts/Python/python-typemaps.swig +++ lldb/scripts/Python/python-typemaps.swig @@ -434,6 +434,22 @@ } } +%typemap(out) lldb::FileSP { + using namespace lldb_private; + $result = nullptr; + lldb::FileSP &sp = $1; + if (sp) { + PythonFile pyfile = unwrapOrSetPythonException(PythonFile::FromFile(*sp)); + if (!pyfile.IsValid()) + return nullptr; + $result = pyfile.release(); + } + if (!$result) + { + $result = Py_None; + Py_INCREF(Py_None); + } +} // FIXME both of these paths wind up calling fdopen() with no provision for ever calling // fclose() on the result. SB interfaces that use FILE* should be deprecated for scripting Index: lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py =================================================================== --- lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py +++ lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py @@ -772,7 +772,6 @@ @add_test_categories(['pyapi']) - @expectedFailureAll() # FIXME implement SBFile::GetFile @skipIf(py_version=['<', (3,)]) def test_identity(self): Index: lldb/include/lldb/Host/File.h =================================================================== --- lldb/include/lldb/Host/File.h +++ lldb/include/lldb/Host/File.h @@ -59,6 +59,8 @@ static mode_t ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options); static llvm::Expected<OpenOptions> GetOptionsFromMode(llvm::StringRef mode); static bool DescriptorIsValid(int descriptor) { return descriptor >= 0; }; + static llvm::Expected<const char *> + GetStreamOpenModeFromOptions(OpenOptions options); File() : IOObject(eFDTypeFile), m_is_interactive(eLazyBoolCalculate), @@ -314,6 +316,31 @@ /// format string \a format. virtual size_t PrintfVarArg(const char *format, va_list args); + /// Return the OpenOptions for this file. + /// + /// Some options like eOpenOptionDontFollowSymlinks only make + /// sense when a file is being opened (or not at all) + /// and may not be preserved for this method. But any valid + /// File should return either or both of eOpenOptionRead and + /// eOpenOptionWrite here. + /// + /// \return + /// OpenOptions flags for this file, or an error. + virtual llvm::Expected<OpenOptions> GetOptions() const; + + static char ID; + + virtual bool isA(const void *classID) const { return classID == &ID; } + + static bool classof(const File *file) { return file->isA(&ID); } + + llvm::Expected<const char *> GetOpenMode() const { + auto opts = GetOptions(); + if (!opts) + return opts.takeError(); + return GetStreamOpenModeFromOptions(opts.get()); + } + /// Get the permissions for a this file. /// /// \return @@ -410,6 +437,13 @@ Status Flush() override; Status Sync() override; size_t PrintfVarArg(const char *format, va_list args) override; + llvm::Expected<OpenOptions> GetOptions() const override; + + static char ID; + virtual bool isA(const void *classID) const override { + return classID == &ID || File::isA(classID); + } + static bool classof(const File *file) { return file->isA(&ID); } protected: bool DescriptorIsValid() const { Index: lldb/include/lldb/API/SBFile.h =================================================================== --- lldb/include/lldb/API/SBFile.h +++ lldb/include/lldb/API/SBFile.h @@ -34,6 +34,8 @@ operator bool() const; bool operator!() const; + FileSP GetFile() const; + private: FileSP m_opaque_sp; };
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits