OperatingSystemPython.cpp revision 4a96ab8a1d4e2222b9f6e415b97bde6b826f94a4
1//===-- OperatingSystemPython.cpp --------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/lldb-python.h"
11
12#ifndef LLDB_DISABLE_PYTHON
13
14#include "OperatingSystemPython.h"
15// C Includes
16// C++ Includes
17// Other libraries and framework includes
18#include "lldb/Core/ArchSpec.h"
19#include "lldb/Core/DataBufferHeap.h"
20#include "lldb/Core/Debugger.h"
21#include "lldb/Core/Module.h"
22#include "lldb/Core/PluginManager.h"
23#include "lldb/Interpreter/PythonDataObjects.h"
24#include "lldb/Core/RegisterValue.h"
25#include "lldb/Core/ValueObjectVariable.h"
26#include "lldb/Interpreter/CommandInterpreter.h"
27#include "lldb/Interpreter/PythonDataObjects.h"
28#include "lldb/Symbol/ClangNamespaceDecl.h"
29#include "lldb/Symbol/ObjectFile.h"
30#include "lldb/Symbol/VariableList.h"
31#include "lldb/Target/Process.h"
32#include "lldb/Target/StopInfo.h"
33#include "lldb/Target/Target.h"
34#include "lldb/Target/ThreadList.h"
35#include "lldb/Target/Thread.h"
36#include "Plugins/Process/Utility/DynamicRegisterInfo.h"
37#include "Plugins/Process/Utility/RegisterContextMemory.h"
38#include "Plugins/Process/Utility/ThreadMemory.h"
39
40using namespace lldb;
41using namespace lldb_private;
42
43void
44OperatingSystemPython::Initialize()
45{
46    PluginManager::RegisterPlugin (GetPluginNameStatic(),
47                                   GetPluginDescriptionStatic(),
48                                   CreateInstance);
49}
50
51void
52OperatingSystemPython::Terminate()
53{
54    PluginManager::UnregisterPlugin (CreateInstance);
55}
56
57OperatingSystem *
58OperatingSystemPython::CreateInstance (Process *process, bool force)
59{
60    // Python OperatingSystem plug-ins must be requested by name, so force must be true
61    FileSpec python_os_plugin_spec (process->GetPythonOSPluginPath());
62    if (python_os_plugin_spec && python_os_plugin_spec.Exists())
63    {
64        std::auto_ptr<OperatingSystemPython> os_ap (new OperatingSystemPython (process, python_os_plugin_spec));
65        if (os_ap.get() && os_ap->IsValid())
66            return os_ap.release();
67    }
68    return NULL;
69}
70
71
72const char *
73OperatingSystemPython::GetPluginNameStatic()
74{
75    return "python";
76}
77
78const char *
79OperatingSystemPython::GetPluginDescriptionStatic()
80{
81    return "Operating system plug-in that gathers OS information from a python class that implements the necessary OperatingSystem functionality.";
82}
83
84
85OperatingSystemPython::OperatingSystemPython (lldb_private::Process *process, const FileSpec &python_module_path) :
86    OperatingSystem (process),
87    m_thread_list_valobj_sp (),
88    m_register_info_ap (),
89    m_interpreter (NULL),
90    m_python_object (NULL)
91{
92    if (!process)
93        return;
94    lldb::TargetSP target_sp = process->CalculateTarget();
95    if (!target_sp)
96        return;
97    m_interpreter = target_sp->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
98    if (m_interpreter)
99    {
100
101        std::string os_plugin_class_name (python_module_path.GetFilename().AsCString(""));
102        if (!os_plugin_class_name.empty())
103        {
104            const bool init_session = false;
105            const bool allow_reload = true;
106            char python_module_path_cstr[PATH_MAX];
107            python_module_path.GetPath(python_module_path_cstr, sizeof(python_module_path_cstr));
108            Error error;
109            if (m_interpreter->LoadScriptingModule (python_module_path_cstr, allow_reload, init_session, error))
110            {
111                // Strip the ".py" extension if there is one
112                size_t py_extension_pos = os_plugin_class_name.rfind(".py");
113                if (py_extension_pos != std::string::npos)
114                    os_plugin_class_name.erase (py_extension_pos);
115                // Add ".OperatingSystemPlugIn" to the module name to get a string like "modulename.OperatingSystemPlugIn"
116                os_plugin_class_name += ".OperatingSystemPlugIn";
117                auto object_sp = m_interpreter->CreateOSPlugin(os_plugin_class_name.c_str(), process->CalculateProcess());
118                if (object_sp)
119                    m_python_object = object_sp->GetObject();
120            }
121        }
122    }
123}
124
125OperatingSystemPython::~OperatingSystemPython ()
126{
127}
128
129DynamicRegisterInfo *
130OperatingSystemPython::GetDynamicRegisterInfo ()
131{
132    if (m_register_info_ap.get() == NULL)
133    {
134        if (!m_interpreter || !m_python_object)
135            return NULL;
136        LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
137
138        if (log)
139            log->Printf ("OperatingSystemPython::GetDynamicRegisterInfo() fetching thread register definitions from python for pid %" PRIu64, m_process->GetID());
140
141        auto object_sp = m_interpreter->OSPlugin_QueryForRegisterInfo(m_interpreter->MakeScriptObject(m_python_object));
142        if (!object_sp)
143            return NULL;
144        PythonDataObject dictionary_data_obj((PyObject*)object_sp->GetObject());
145        PythonDataDictionary dictionary = dictionary_data_obj.GetDictionaryObject();
146        if (!dictionary)
147            return NULL;
148
149        m_register_info_ap.reset (new DynamicRegisterInfo (dictionary));
150        assert (m_register_info_ap->GetNumRegisters() > 0);
151        assert (m_register_info_ap->GetNumRegisterSets() > 0);
152    }
153    return m_register_info_ap.get();
154}
155
156//------------------------------------------------------------------
157// PluginInterface protocol
158//------------------------------------------------------------------
159const char *
160OperatingSystemPython::GetPluginName()
161{
162    return "OperatingSystemPython";
163}
164
165const char *
166OperatingSystemPython::GetShortPluginName()
167{
168    return GetPluginNameStatic();
169}
170
171uint32_t
172OperatingSystemPython::GetPluginVersion()
173{
174    return 1;
175}
176
177bool
178OperatingSystemPython::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list)
179{
180    if (!m_interpreter || !m_python_object)
181        return NULL;
182
183    LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
184
185    // First thing we have to do is get the API lock, and the run lock.  We're going to change the thread
186    // content of the process, and we're going to use python, which requires the API lock to do it.
187    // So get & hold that.  This is a recursive lock so we can grant it to any Python code called on the stack below us.
188    Target &target = m_process->GetTarget();
189    Mutex::Locker api_locker (target.GetAPIMutex());
190
191    if (log)
192        log->Printf ("OperatingSystemPython::UpdateThreadList() fetching thread data from python for pid %" PRIu64, m_process->GetID());
193
194    auto object_sp = m_interpreter->OSPlugin_QueryForThreadsInfo(m_interpreter->MakeScriptObject(m_python_object));
195    if (!object_sp)
196        return NULL;
197    PythonDataObject pyobj((PyObject*)object_sp->GetObject());
198    PythonDataArray threads_array (pyobj.GetArrayObject());
199    if (threads_array)
200    {
201//        const uint32_t num_old_threads = old_thread_list.GetSize(false);
202//        for (uint32_t i=0; i<num_old_threads; ++i)
203//        {
204//            ThreadSP old_thread_sp(old_thread_list.GetThreadAtIndex(i, false));
205//            if (old_thread_sp->GetID() < 0x10000)
206//                new_thread_list.AddThread (old_thread_sp);
207//        }
208
209        PythonDataString tid_pystr("tid");
210        PythonDataString name_pystr("name");
211        PythonDataString queue_pystr("queue");
212        PythonDataString state_pystr("state");
213        PythonDataString stop_reason_pystr("stop_reason");
214        PythonDataString reg_data_addr_pystr ("register_data_addr");
215
216        const uint32_t num_threads = threads_array.GetSize();
217        for (uint32_t i=0; i<num_threads; ++i)
218        {
219            PythonDataDictionary thread_dict(threads_array.GetItemAtIndex(i).GetDictionaryObject());
220            if (thread_dict)
221            {
222                const tid_t tid = thread_dict.GetItemForKeyAsInteger (tid_pystr, LLDB_INVALID_THREAD_ID);
223                const addr_t reg_data_addr = thread_dict.GetItemForKeyAsInteger (reg_data_addr_pystr, LLDB_INVALID_ADDRESS);
224                const char *name = thread_dict.GetItemForKeyAsString (name_pystr);
225                const char *queue = thread_dict.GetItemForKeyAsString (queue_pystr);
226                //const char *state = thread_dict.GetItemForKeyAsString (state_pystr);
227                //const char *stop_reason = thread_dict.GetItemForKeyAsString (stop_reason_pystr);
228
229                ThreadSP thread_sp (old_thread_list.FindThreadByID (tid, false));
230                if (!thread_sp)
231                    thread_sp.reset (new ThreadMemory (*m_process,
232                                                       tid,
233                                                       name,
234                                                       queue,
235                                                       reg_data_addr));
236                new_thread_list.AddThread(thread_sp);
237
238            }
239        }
240    }
241    else
242    {
243        new_thread_list = old_thread_list;
244    }
245    return new_thread_list.GetSize(false) > 0;
246}
247
248void
249OperatingSystemPython::ThreadWasSelected (Thread *thread)
250{
251}
252
253RegisterContextSP
254OperatingSystemPython::CreateRegisterContextForThread (Thread *thread, lldb::addr_t reg_data_addr)
255{
256    RegisterContextSP reg_ctx_sp;
257    if (!m_interpreter || !m_python_object || !thread)
258        return RegisterContextSP();
259
260    // First thing we have to do is get the API lock, and the run lock.  We're going to change the thread
261    // content of the process, and we're going to use python, which requires the API lock to do it.
262    // So get & hold that.  This is a recursive lock so we can grant it to any Python code called on the stack below us.
263    Target &target = m_process->GetTarget();
264    Mutex::Locker api_locker (target.GetAPIMutex());
265
266    LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
267
268    if (reg_data_addr != LLDB_INVALID_ADDRESS)
269    {
270        // The registers data is in contiguous memory, just create the register
271        // context using the address provided
272        if (log)
273            log->Printf ("OperatingSystemPython::CreateRegisterContextForThread (tid = 0x%" PRIx64 ", reg_data_addr = 0x%" PRIx64 ") creating memory register context", thread->GetID(), reg_data_addr);
274        reg_ctx_sp.reset (new RegisterContextMemory (*thread, 0, *GetDynamicRegisterInfo (), reg_data_addr));
275    }
276    else
277    {
278        // No register data address is provided, query the python plug-in to let
279        // it make up the data as it sees fit
280        if (log)
281            log->Printf ("OperatingSystemPython::CreateRegisterContextForThread (tid = 0x%" PRIx64 ") fetching register data from python", thread->GetID());
282
283        auto object_sp = m_interpreter->OSPlugin_QueryForRegisterContextData (m_interpreter->MakeScriptObject(m_python_object),
284                                                                              thread->GetID());
285
286        if (!object_sp)
287            return RegisterContextSP();
288
289        PythonDataString reg_context_data((PyObject*)object_sp->GetObject());
290        if (reg_context_data)
291        {
292            DataBufferSP data_sp (new DataBufferHeap (reg_context_data.GetString(),
293                                                      reg_context_data.GetSize()));
294            if (data_sp->GetByteSize())
295            {
296                RegisterContextMemory *reg_ctx_memory = new RegisterContextMemory (*thread, 0, *GetDynamicRegisterInfo (), LLDB_INVALID_ADDRESS);
297                if (reg_ctx_memory)
298                {
299                    reg_ctx_sp.reset(reg_ctx_memory);
300                    reg_ctx_memory->SetAllRegisterData (data_sp);
301                }
302            }
303        }
304    }
305    return reg_ctx_sp;
306}
307
308StopInfoSP
309OperatingSystemPython::CreateThreadStopReason (lldb_private::Thread *thread)
310{
311    // We should have gotten the thread stop info from the dictionary of data for
312    // the thread in the initial call to get_thread_info(), this should have been
313    // cached so we can return it here
314    StopInfoSP stop_info_sp; //(StopInfo::CreateStopReasonWithSignal (*thread, SIGSTOP));
315    return stop_info_sp;
316}
317
318
319#endif // #ifndef LLDB_DISABLE_PYTHON
320