AppleObjCRuntimeV1.cpp revision ae2ae94bd72daf435204e99a0e03ccc64470a843
1//===-- AppleObjCRuntimeV1.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 "AppleObjCRuntimeV1.h"
11#include "AppleObjCTrampolineHandler.h"
12
13#include "llvm/Support/MachO.h"
14#include "clang/AST/Type.h"
15
16#include "lldb/Breakpoint/BreakpointLocation.h"
17#include "lldb/Core/ConstString.h"
18#include "lldb/Core/Error.h"
19#include "lldb/Core/Log.h"
20#include "lldb/Core/Module.h"
21#include "lldb/Core/PluginManager.h"
22#include "lldb/Core/Scalar.h"
23#include "lldb/Core/StreamString.h"
24#include "lldb/Expression/ClangFunction.h"
25#include "lldb/Expression/ClangUtilityFunction.h"
26#include "lldb/Symbol/ClangASTContext.h"
27#include "lldb/Target/ExecutionContext.h"
28#include "lldb/Target/Process.h"
29#include "lldb/Target/RegisterContext.h"
30#include "lldb/Target/Target.h"
31#include "lldb/Target/Thread.h"
32
33#include <vector>
34
35using namespace lldb;
36using namespace lldb_private;
37
38static const char *pluginName = "AppleObjCRuntimeV1";
39static const char *pluginDesc = "Apple Objective C Language Runtime - Version 1";
40static const char *pluginShort = "language.apple.objc.v1";
41
42bool
43AppleObjCRuntimeV1::GetDynamicTypeAndAddress (ValueObject &in_value,
44                                             lldb::DynamicValueType use_dynamic,
45                                             TypeAndOrName &class_type_or_name,
46                                             Address &address)
47{
48    return false;
49}
50
51//------------------------------------------------------------------
52// Static Functions
53//------------------------------------------------------------------
54lldb_private::LanguageRuntime *
55AppleObjCRuntimeV1::CreateInstance (Process *process, lldb::LanguageType language)
56{
57    // FIXME: This should be a MacOS or iOS process, and we need to look for the OBJC section to make
58    // sure we aren't using the V1 runtime.
59    if (language == eLanguageTypeObjC)
60    {
61        ModuleSP objc_module_sp;
62
63        if (AppleObjCRuntime::GetObjCVersion (process, objc_module_sp) == eAppleObjC_V1)
64            return new AppleObjCRuntimeV1 (process);
65        else
66            return NULL;
67    }
68    else
69        return NULL;
70}
71
72void
73AppleObjCRuntimeV1::Initialize()
74{
75    PluginManager::RegisterPlugin (pluginName,
76                                   pluginDesc,
77                                   CreateInstance);
78}
79
80void
81AppleObjCRuntimeV1::Terminate()
82{
83    PluginManager::UnregisterPlugin (CreateInstance);
84}
85
86//------------------------------------------------------------------
87// PluginInterface protocol
88//------------------------------------------------------------------
89const char *
90AppleObjCRuntimeV1::GetPluginName()
91{
92    return pluginName;
93}
94
95const char *
96AppleObjCRuntimeV1::GetShortPluginName()
97{
98    return pluginShort;
99}
100
101uint32_t
102AppleObjCRuntimeV1::GetPluginVersion()
103{
104    return 1;
105}
106
107BreakpointResolverSP
108AppleObjCRuntimeV1::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp)
109{
110    BreakpointResolverSP resolver_sp;
111
112    if (throw_bp)
113        resolver_sp.reset (new BreakpointResolverName (bkpt,
114                                                       "objc_exception_throw",
115                                                       eFunctionNameTypeBase,
116                                                       Breakpoint::Exact,
117                                                       eLazyBoolNo));
118    // FIXME: don't do catch yet.
119    return resolver_sp;
120}
121
122struct BufStruct {
123    char contents[2048];
124};
125
126ClangUtilityFunction *
127AppleObjCRuntimeV1::CreateObjectChecker(const char *name)
128{
129    std::auto_ptr<BufStruct> buf(new BufStruct);
130
131    assert(snprintf(&buf->contents[0], sizeof(buf->contents),
132                    "struct __objc_class                                                    \n"
133                    "{                                                                      \n"
134                    "   struct __objc_class *isa;                                           \n"
135                    "   struct __objc_class *super_class;                                   \n"
136                    "   const char *name;                                                   \n"
137                    "   // rest of struct elided because unused                             \n"
138                    "};                                                                     \n"
139                    "                                                                       \n"
140                    "struct __objc_object                                                   \n"
141                    "{                                                                      \n"
142                    "   struct __objc_class *isa;                                           \n"
143                    "};                                                                     \n"
144                    "                                                                       \n"
145                    "extern \"C\" void                                                      \n"
146                    "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector)                  \n"
147                    "{                                                                      \n"
148                    "   struct __objc_object *obj = (struct __objc_object*)$__lldb_arg_obj; \n"
149                    "   (int)strlen(obj->isa->name);                                        \n"
150                    "}                                                                      \n",
151                    name) < sizeof(buf->contents));
152
153    return new ClangUtilityFunction(buf->contents, name);
154}
155
156// this code relies on the assumption that an Objective-C object always starts
157// with an ISA at offset 0.
158ObjCLanguageRuntime::ObjCISA
159AppleObjCRuntimeV1::GetISA(ValueObject& valobj)
160{
161    if (ClangASTType::GetMinimumLanguage(valobj.GetClangAST(),valobj.GetClangType()) != eLanguageTypeObjC)
162        return 0;
163
164    // if we get an invalid VO (which might still happen when playing around
165    // with pointers returned by the expression parser, don't consider this
166    // a valid ObjC object)
167    if (valobj.GetValue().GetContextType() == Value::eContextTypeInvalid)
168        return 0;
169
170    addr_t isa_pointer = valobj.GetPointerValue();
171
172    ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
173
174    Process *process = exe_ctx.GetProcessPtr();
175    if (process)
176    {
177        uint8_t pointer_size = process->GetAddressByteSize();
178
179        Error error;
180        return process->ReadUnsignedIntegerFromMemory (isa_pointer,
181                                                       pointer_size,
182                                                       0,
183                                                       error);
184    }
185    return 0;
186}
187
188AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1 (ValueObject &isa_pointer)
189{
190    ObjCISA ptr_value = isa_pointer.GetValueAsUnsigned(0);
191
192    lldb::ProcessSP process_sp = isa_pointer.GetProcessSP();
193
194    Initialize (ptr_value,process_sp);
195}
196
197AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1 (ObjCISA isa, lldb::ProcessSP process_sp)
198{
199    Initialize (isa, process_sp);
200}
201
202void
203AppleObjCRuntimeV1::ClassDescriptorV1::Initialize (ObjCISA isa, lldb::ProcessSP process_sp)
204{
205    if (!isa || !process_sp)
206    {
207        m_valid = false;
208        return;
209    }
210
211    m_valid = true;
212
213    Error error;
214
215    m_isa = process_sp->ReadPointerFromMemory(isa, error);
216
217    if (error.Fail())
218    {
219        m_valid = false;
220        return;
221    }
222
223    uint32_t ptr_size = process_sp->GetAddressByteSize();
224
225    if (!IsPointerValid(m_isa,ptr_size))
226    {
227        m_valid = false;
228        return;
229    }
230
231    m_parent_isa = process_sp->ReadPointerFromMemory(m_isa + ptr_size,error);
232
233    if (error.Fail())
234    {
235        m_valid = false;
236        return;
237    }
238
239    if (!IsPointerValid(m_parent_isa,ptr_size,true))
240    {
241        m_valid = false;
242        return;
243    }
244
245    lldb::addr_t name_ptr = process_sp->ReadPointerFromMemory(m_isa + 2 * ptr_size,error);
246
247    if (error.Fail())
248    {
249        m_valid = false;
250        return;
251    }
252
253    lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
254
255    size_t count = process_sp->ReadCStringFromMemory(name_ptr, (char*)buffer_sp->GetBytes(), 1024, error);
256
257    if (error.Fail())
258    {
259        m_valid = false;
260        return;
261    }
262
263    if (count)
264        m_name = ConstString((char*)buffer_sp->GetBytes());
265    else
266        m_name = ConstString();
267
268    m_instance_size = process_sp->ReadUnsignedIntegerFromMemory(m_isa + 5 * ptr_size, ptr_size, 0, error);
269
270    if (error.Fail())
271    {
272        m_valid = false;
273        return;
274    }
275
276    m_process_wp = lldb::ProcessWP(process_sp);
277}
278
279AppleObjCRuntime::ClassDescriptorSP
280AppleObjCRuntimeV1::ClassDescriptorV1::GetSuperclass ()
281{
282    if (!m_valid)
283        return NULL;
284    ProcessSP process_sp = m_process_wp.lock();
285    if (!process_sp)
286        return NULL;
287    return ObjCLanguageRuntime::ClassDescriptorSP(new AppleObjCRuntimeV1::ClassDescriptorV1(m_parent_isa,process_sp));
288}
289
290ObjCLanguageRuntime::ClassDescriptorSP
291AppleObjCRuntimeV1::GetClassDescriptor (ValueObject& in_value)
292{
293    ObjCISA isa = GetISA(in_value);
294
295    ObjCLanguageRuntime::ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa);
296    ObjCLanguageRuntime::ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end();
297
298    if (found != end && found->second)
299        return found->second;
300
301    ClassDescriptorSP descriptor = ClassDescriptorSP(new ClassDescriptorV1(in_value));
302    if (descriptor && descriptor->IsValid())
303        m_isa_to_descriptor_cache[descriptor->GetISA()] = descriptor;
304    return descriptor;
305}
306
307ObjCLanguageRuntime::ClassDescriptorSP
308AppleObjCRuntimeV1::GetClassDescriptor (ObjCISA isa)
309{
310    ObjCLanguageRuntime::ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa);
311    ObjCLanguageRuntime::ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end();
312
313    if (found != end && found->second)
314        return found->second;
315
316    ClassDescriptorSP descriptor = ClassDescriptorSP(new ClassDescriptorV1(isa,m_process->CalculateProcess()));
317    if (descriptor && descriptor->IsValid())
318        m_isa_to_descriptor_cache[descriptor->GetISA()] = descriptor;
319    return descriptor;
320}
321