diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python')
4 files changed, 315 insertions, 70 deletions
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp index 23bacc9..1fdf4c7 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -19,10 +19,15 @@ #include "lldb/Core/Stream.h" #include "lldb/Host/File.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Interpreter/ScriptInterpreter.h" +#include "llvm/Support/ConvertUTF.h" + #include <stdio.h> +#include "llvm/ADT/StringSwitch.h" + using namespace lldb_private; using namespace lldb; @@ -81,6 +86,8 @@ PythonObject::GetObjectType() const if (PythonBytes::Check(m_py_obj)) return PyObjectType::Bytes; #endif + if (PythonByteArray::Check(m_py_obj)) + return PyObjectType::ByteArray; if (PythonInteger::Check(m_py_obj)) return PyObjectType::Integer; if (PythonFile::Check(m_py_obj)) @@ -216,6 +223,8 @@ PythonObject::CreateStructuredObject() const return PythonString(PyRefType::Borrowed, m_py_obj).CreateStructuredString(); case PyObjectType::Bytes: return PythonBytes(PyRefType::Borrowed, m_py_obj).CreateStructuredString(); + case PyObjectType::ByteArray: + return PythonByteArray(PyRefType::Borrowed, m_py_obj).CreateStructuredString(); case PyObjectType::None: return StructuredData::ObjectSP(); default: @@ -321,6 +330,87 @@ PythonBytes::CreateStructuredString() const return result; } +PythonByteArray::PythonByteArray(llvm::ArrayRef<uint8_t> bytes) : PythonByteArray(bytes.data(), bytes.size()) +{ +} + +PythonByteArray::PythonByteArray(const uint8_t *bytes, size_t length) +{ + const char *str = reinterpret_cast<const char *>(bytes); + Reset(PyRefType::Owned, PyByteArray_FromStringAndSize(str, length)); +} + +PythonByteArray::PythonByteArray(PyRefType type, PyObject *o) +{ + Reset(type, o); +} + +PythonByteArray::PythonByteArray(const PythonBytes &object) : PythonObject(object) +{ +} + +PythonByteArray::~PythonByteArray() +{ +} + +bool +PythonByteArray::Check(PyObject *py_obj) +{ + if (!py_obj) + return false; + if (PyByteArray_Check(py_obj)) + return true; + return false; +} + +void +PythonByteArray::Reset(PyRefType type, PyObject *py_obj) +{ + // Grab the desired reference type so that if we end up rejecting + // `py_obj` it still gets decremented if necessary. + PythonObject result(type, py_obj); + + if (!PythonByteArray::Check(py_obj)) + { + PythonObject::Reset(); + return; + } + + // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls + // back into the virtual implementation. + PythonObject::Reset(PyRefType::Borrowed, result.get()); +} + +llvm::ArrayRef<uint8_t> +PythonByteArray::GetBytes() const +{ + if (!IsValid()) + return llvm::ArrayRef<uint8_t>(); + + char *c = PyByteArray_AsString(m_py_obj); + size_t size = GetSize(); + return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size); +} + +size_t +PythonByteArray::GetSize() const +{ + if (!IsValid()) + return 0; + + return PyByteArray_Size(m_py_obj); +} + +StructuredData::StringSP +PythonByteArray::CreateStructuredString() const +{ + StructuredData::StringSP result(new StructuredData::String); + llvm::ArrayRef<uint8_t> bytes = GetBytes(); + const char *str = reinterpret_cast<const char *>(bytes.data()); + result->SetValue(std::string(str, bytes.size())); + return result; +} + //---------------------------------------------------------------------- // PythonString //---------------------------------------------------------------------- @@ -1019,13 +1109,37 @@ PythonCallable::Reset(PyRefType type, PyObject *py_obj) PythonCallable::ArgInfo PythonCallable::GetNumArguments() const { - ArgInfo result = { 0, false, false }; + ArgInfo result = { 0, false, false, false }; if (!IsValid()) return result; PyObject *py_func_obj = m_py_obj; if (PyMethod_Check(py_func_obj)) + { py_func_obj = PyMethod_GET_FUNCTION(py_func_obj); + PythonObject im_self = GetAttributeValue("im_self"); + if (im_self.IsValid() && !im_self.IsNone()) + result.is_bound_method = true; + } + else + { + // see if this is a callable object with an __call__ method + if (!PyFunction_Check(py_func_obj)) + { + PythonObject __call__ = GetAttributeValue("__call__"); + if (__call__.IsValid()) + { + auto __callable__ = __call__.AsType<PythonCallable>(); + if (__callable__.IsValid()) + { + py_func_obj = PyMethod_GET_FUNCTION(__callable__.get()); + PythonObject im_self = GetAttributeValue("im_self"); + if (im_self.IsValid() && !im_self.IsNone()) + result.is_bound_method = true; + } + } + } + } if (!py_func_obj) return result; @@ -1075,9 +1189,7 @@ PythonFile::PythonFile(File &file, const char *mode) PythonFile::PythonFile(const char *path, const char *mode) { - FILE *fp = nullptr; - fp = fopen(path, mode); - lldb_private::File file(fp, true); + lldb_private::File file(path, GetOptionsFromMode(mode)); Reset(file, mode); } @@ -1156,6 +1268,22 @@ PythonFile::Reset(File &file, const char *mode) #endif } +uint32_t +PythonFile::GetOptionsFromMode(llvm::StringRef mode) +{ + if (mode.empty()) + return 0; + + return llvm::StringSwitch<uint32_t>(mode.str().c_str()) + .Case("r", File::eOpenOptionRead) + .Case("w", File::eOpenOptionWrite) + .Case("a", File::eOpenOptionWrite|File::eOpenOptionAppend|File::eOpenOptionCanCreate) + .Case("r+", File::eOpenOptionRead|File::eOpenOptionWrite) + .Case("w+", File::eOpenOptionRead|File::eOpenOptionWrite|File::eOpenOptionCanCreate|File::eOpenOptionTruncate) + .Case("a+", File::eOpenOptionRead|File::eOpenOptionWrite|File::eOpenOptionAppend|File::eOpenOptionCanCreate) + .Default(0); +} + bool PythonFile::GetUnderlyingFile(File &file) const { @@ -1166,6 +1294,8 @@ PythonFile::GetUnderlyingFile(File &file) const // We don't own the file descriptor returned by this function, make sure the // File object knows about that. file.SetDescriptor(PyObject_AsFileDescriptor(m_py_obj), false); + PythonString py_mode = GetAttributeValue("mode").AsType<PythonString>(); + file.SetOptions(PythonFile::GetOptionsFromMode(py_mode.GetString())); return file.IsValid(); } diff --git a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h index 06264b6..78245a9 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h +++ b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -75,6 +75,7 @@ enum class PyObjectType List, String, Bytes, + ByteArray, Module, Callable, Tuple, @@ -293,6 +294,39 @@ public: CreateStructuredString() const; }; +class PythonByteArray : public PythonObject +{ +public: + PythonByteArray(); + explicit PythonByteArray(llvm::ArrayRef<uint8_t> bytes); + PythonByteArray(const uint8_t *bytes, size_t length); + PythonByteArray(PyRefType type, PyObject *o); + PythonByteArray(const PythonBytes &object); + + ~PythonByteArray() override; + + static bool + Check(PyObject *py_obj); + + // Bring in the no-argument base class version + using PythonObject::Reset; + + void + Reset(PyRefType type, PyObject *py_obj) override; + + llvm::ArrayRef<uint8_t> + GetBytes() const; + + size_t + GetSize() const; + + void + SetBytes(llvm::ArrayRef<uint8_t> stringbytes); + + StructuredData::StringSP + CreateStructuredString() const; +}; + class PythonString : public PythonObject { public: @@ -468,6 +502,7 @@ class PythonCallable : public PythonObject public: struct ArgInfo { size_t count; + bool is_bound_method : 1; bool has_varargs : 1; bool has_kwargs : 1; }; @@ -525,6 +560,8 @@ class PythonFile : public PythonObject void Reset(PyRefType type, PyObject *py_obj) override; void Reset(File &file, const char *mode); + static uint32_t GetOptionsFromMode(llvm::StringRef mode); + bool GetUnderlyingFile(File &file) const; }; diff --git a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 19ad86d..7881673 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -146,7 +146,7 @@ private: size_t size = 0; static wchar_t *g_python_home = Py_DecodeLocale(LLDB_PYTHON_HOME, &size); #else - static char *g_python_home = LLDB_PYTHON_HOME; + static char g_python_home[] = LLDB_PYTHON_HOME; #endif Py_SetPythonHome(g_python_home); #endif @@ -274,7 +274,7 @@ ScriptInterpreterPython::ScriptInterpreterPython(CommandInterpreter &interpreter m_lock_count(0), m_command_thread_state(nullptr) { - assert(g_initialized && "ScriptInterpreterPython created but InitializePrivate has not been called!"); + InitializePrivate(); m_dictionary_name.append("_dict"); StreamString run_string; @@ -330,8 +330,6 @@ ScriptInterpreterPython::Initialize() std::call_once(g_once_flag, []() { - InitializePrivate(); - PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), lldb::eScriptLanguagePython, @@ -547,6 +545,27 @@ ScriptInterpreterPython::LeaveSession () } bool +ScriptInterpreterPython::SetStdHandle(File &file, const char *py_name, PythonFile &save_file, const char *mode) +{ + if (file.IsValid()) + { + // Flush the file before giving it to python to avoid interleaved output. + file.Flush(); + + PythonDictionary &sys_module_dict = GetSysModuleDictionary(); + + save_file = sys_module_dict.GetItemForKey(PythonString(py_name)).AsType<PythonFile>(); + + PythonFile new_file(file, mode); + sys_module_dict.SetItemForKey(PythonString(py_name), new_file); + return true; + } + else + save_file.Reset(); + return false; +} + +bool ScriptInterpreterPython::EnterSession (uint16_t on_entry_flags, FILE *in, FILE *out, @@ -604,54 +623,31 @@ ScriptInterpreterPython::EnterSession (uint16_t on_entry_flags, if (!in_file.IsValid() || !out_file.IsValid() || !err_file.IsValid()) m_interpreter.GetDebugger().AdoptTopIOHandlerFilesIfInvalid (in_sp, out_sp, err_sp); - m_saved_stdin.Reset(); - if ((on_entry_flags & Locker::NoSTDIN) == 0) + if (on_entry_flags & Locker::NoSTDIN) + { + m_saved_stdin.Reset(); + } + else { - // STDIN is enabled - if (!in_file.IsValid() && in_sp) - in_file = in_sp->GetFile(); - if (in_file.IsValid()) + if (!SetStdHandle(in_file, "stdin", m_saved_stdin, "r")) { - // Flush the file before giving it to python to avoid interleaved output. - in_file.Flush(); - - m_saved_stdin = sys_module_dict.GetItemForKey(PythonString("stdin")).AsType<PythonFile>(); - // This call can deadlock your process if the file is locked - PythonFile new_file(in_file, "r"); - sys_module_dict.SetItemForKey (PythonString("stdin"), new_file); + if (in_sp) + SetStdHandle(in_sp->GetFile(), "stdin", m_saved_stdin, "r"); } } - if (!out_file.IsValid() && out_sp) - out_file = out_sp->GetFile(); - if (out_file.IsValid()) + if (!SetStdHandle(out_file, "stdout", m_saved_stdout, "w")) { - // Flush the file before giving it to python to avoid interleaved output. - out_file.Flush(); - - m_saved_stdout = sys_module_dict.GetItemForKey(PythonString("stdout")).AsType<PythonFile>(); - - PythonFile new_file(out_file, "w"); - sys_module_dict.SetItemForKey (PythonString("stdout"), new_file); + if (out_sp) + SetStdHandle(out_sp->GetFile(), "stdout", m_saved_stdout, "w"); } - else - m_saved_stdout.Reset(); - if (!err_file.IsValid() && err_sp) - err_file = err_sp->GetFile(); - if (err_file.IsValid()) + if (!SetStdHandle(err_file, "stderr", m_saved_stderr, "w")) { - // Flush the file before giving it to python to avoid interleaved output. - err_file.Flush(); - - m_saved_stderr = sys_module_dict.GetItemForKey(PythonString("stderr")).AsType<PythonFile>(); - - PythonFile new_file(err_file, "w"); - sys_module_dict.SetItemForKey (PythonString("stderr"), new_file); + if (err_sp) + SetStdHandle(err_sp->GetFile(), "stderr", m_saved_stderr, "w"); } - else - m_saved_stderr.Reset(); } if (PyErr_Occurred()) @@ -1019,7 +1015,7 @@ ScriptInterpreterPython::Interrupt() if (IsExecutingPython()) { - PyThreadState *state = PyThreadState_Get(); + PyThreadState *state = PyThreadState_GET(); if (!state) state = GetThreadState(); if (state) @@ -1555,10 +1551,12 @@ ScriptInterpreterPython::OSPlugin_RegisterInfo(StructuredData::ObjectSP os_plugi PyErr_Print(); PyErr_Clear(); } - assert(PythonDictionary::Check(py_return.get()) && "get_register_info returned unknown object type!"); - - PythonDictionary result_dict(PyRefType::Borrowed, py_return.get()); - return result_dict.CreateStructuredDictionary(); + if (py_return.get()) + { + PythonDictionary result_dict(PyRefType::Borrowed, py_return.get()); + return result_dict.CreateStructuredDictionary(); + } + return StructuredData::DictionarySP(); } StructuredData::ArraySP @@ -1611,10 +1609,12 @@ ScriptInterpreterPython::OSPlugin_ThreadsInfo(StructuredData::ObjectSP os_plugin PyErr_Clear(); } - assert(PythonList::Check(py_return.get()) && "get_thread_info returned unknown object type!"); - - PythonList result_list(PyRefType::Borrowed, py_return.get()); - return result_list.CreateStructuredArray(); + if (py_return.get()) + { + PythonList result_list(PyRefType::Borrowed, py_return.get()); + return result_list.CreateStructuredArray(); + } + return StructuredData::ArraySP(); } // GetPythonValueFormatString provides a system independent type safe way to @@ -1692,10 +1692,12 @@ ScriptInterpreterPython::OSPlugin_RegisterContextData(StructuredData::ObjectSP o PyErr_Clear(); } - assert(PythonBytes::Check(py_return.get()) && "get_register_data returned unknown object type!"); - - PythonBytes result(PyRefType::Borrowed, py_return.get()); - return result.CreateStructuredString(); + if (py_return.get()) + { + PythonBytes result(PyRefType::Borrowed, py_return.get()); + return result.CreateStructuredString(); + } + return StructuredData::StringSP(); } StructuredData::DictionarySP @@ -1750,10 +1752,12 @@ ScriptInterpreterPython::OSPlugin_CreateThread(StructuredData::ObjectSP os_plugi PyErr_Clear(); } - assert(PythonDictionary::Check(py_return.get()) && "create_thread returned unknown object type!"); - - PythonDictionary result_dict(PyRefType::Borrowed, py_return.get()); - return result_dict.CreateStructuredDictionary(); + if (py_return.get()) + { + PythonDictionary result_dict(PyRefType::Borrowed, py_return.get()); + return result_dict.CreateStructuredDictionary(); + } + return StructuredData::DictionarySP(); } StructuredData::ObjectSP @@ -2353,6 +2357,72 @@ ScriptInterpreterPython::GetSyntheticValue(const StructuredData::ObjectSP &imple return ret_val; } +ConstString +ScriptInterpreterPython::GetSyntheticTypeName (const StructuredData::ObjectSP &implementor_sp) +{ + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + + static char callee_name[] = "get_type_name"; + + ConstString ret_val; + bool got_string = false; + std::string buffer; + + if (!implementor_sp) + return ret_val; + + StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); + if (!generic) + return ret_val; + PythonObject implementor(PyRefType::Borrowed, (PyObject *)generic->GetValue()); + if (!implementor.IsAllocated()) + return ret_val; + + PythonObject pmeth(PyRefType::Owned, PyObject_GetAttrString(implementor.get(), callee_name)); + + if (PyErr_Occurred()) + PyErr_Clear(); + + if (!pmeth.IsAllocated()) + return ret_val; + + if (PyCallable_Check(pmeth.get()) == 0) + { + if (PyErr_Occurred()) + PyErr_Clear(); + return ret_val; + } + + if (PyErr_Occurred()) + PyErr_Clear(); + + // right now we know this function exists and is callable.. + PythonObject py_return(PyRefType::Owned, PyObject_CallMethod(implementor.get(), callee_name, nullptr)); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) + { + PyErr_Print(); + PyErr_Clear(); + } + + if (py_return.IsAllocated() && PythonString::Check(py_return.get())) + { + PythonString py_string(PyRefType::Borrowed, py_return.get()); + llvm::StringRef return_data(py_string.GetString()); + if (!return_data.empty()) + { + buffer.assign(return_data.data(), return_data.size()); + got_string = true; + } + } + + if (got_string) + ret_val.SetCStringWithLength(buffer.c_str(), buffer.size()); + + return ret_val; +} + bool ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, Process* process, @@ -2550,7 +2620,7 @@ ScriptInterpreterPython::LoadScriptingModule(const char *pathname, bool can_relo StreamString command_stream; - // Before executing Pyton code, lock the GIL. + // Before executing Python code, lock the GIL. Locker py_lock (this, Locker::AcquireLock | (init_session ? Locker::InitSession : 0) | Locker::NoSTDIN, Locker::FreeAcquiredLock | (init_session ? Locker::TearDownSession : 0)); @@ -2571,9 +2641,10 @@ ScriptInterpreterPython::LoadScriptingModule(const char *pathname, bool can_relo target_file.GetFileType() == FileSpec::eFileTypeRegular || target_file.GetFileType() == FileSpec::eFileTypeSymbolicLink) { - std::string directory(target_file.GetDirectory().GetCString()); - replace_all(directory,"'","\\'"); - + std::string directory = target_file.GetDirectory().GetCString(); + replace_all(directory, "\\", "\\\\"); + replace_all(directory, "'", "\\'"); + // now make sure that Python has "directory" in the search path StreamString command_stream; command_stream.Printf("if not (sys.path.__contains__('%s')):\n sys.path.insert(1,'%s');\n\n", @@ -2585,7 +2656,7 @@ ScriptInterpreterPython::LoadScriptingModule(const char *pathname, bool can_relo error.SetErrorString("Python sys.path handling failed"); return false; } - + // strip .py or .pyc extension ConstString extension = target_file.GetFileNameExtension(); if (extension) @@ -2636,8 +2707,8 @@ ScriptInterpreterPython::LoadScriptingModule(const char *pathname, bool can_relo command_stream.Printf("reload_module(%s)",basename.c_str()); } else - command_stream.Printf("import %s",basename.c_str()); - + command_stream.Printf("import %s", basename.c_str()); + error = ExecuteMultipleLines(command_stream.GetData(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)); if (error.Fail()) return false; @@ -3098,7 +3169,9 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb void ScriptInterpreterPython::InitializePrivate () { - assert(!g_initialized && "ScriptInterpreterPython::InitializePrivate() called more than once!"); + if (g_initialized) + return; + g_initialized = true; Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); diff --git a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h index 4c6eb39..263bb52 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h +++ b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h @@ -228,6 +228,8 @@ public: lldb::ValueObjectSP GetSyntheticValue(const StructuredData::ObjectSP &implementor) override; + ConstString GetSyntheticTypeName (const StructuredData::ObjectSP &implementor) override; + bool RunScriptBasedCommand(const char* impl_function, const char* args, @@ -581,6 +583,9 @@ protected: bool GetEmbeddedInterpreterModuleObjects (); + bool + SetStdHandle(File &file, const char *py_name, PythonFile &save_file, const char *mode); + PythonFile m_saved_stdin; PythonFile m_saved_stdout; PythonFile m_saved_stderr; |