1//===-- ItaniumABILanguageRuntime.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 "ItaniumABILanguageRuntime.h"
11
12#include "lldb/Breakpoint/BreakpointLocation.h"
13#include "lldb/Core/ConstString.h"
14#include "lldb/Core/Error.h"
15#include "lldb/Core/Log.h"
16#include "lldb/Core/Module.h"
17#include "lldb/Core/PluginManager.h"
18#include "lldb/Core/Scalar.h"
19#include "lldb/Core/ValueObject.h"
20#include "lldb/Core/ValueObjectMemory.h"
21#include "lldb/Symbol/ClangASTContext.h"
22#include "lldb/Symbol/Symbol.h"
23#include "lldb/Symbol/TypeList.h"
24#include "lldb/Target/Process.h"
25#include "lldb/Target/RegisterContext.h"
26#include "lldb/Target/StopInfo.h"
27#include "lldb/Target/Target.h"
28#include "lldb/Target/Thread.h"
29
30#include <vector>
31
32using namespace lldb;
33using namespace lldb_private;
34
35static const char *vtable_demangled_prefix = "vtable for ";
36
37bool
38ItaniumABILanguageRuntime::CouldHaveDynamicValue (ValueObject &in_value)
39{
40    const bool check_cxx = true;
41    const bool check_objc = false;
42    return in_value.GetClangType().IsPossibleDynamicType (NULL, check_cxx, check_objc);
43}
44
45bool
46ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,
47                                                     lldb::DynamicValueType use_dynamic,
48                                                     TypeAndOrName &class_type_or_name,
49                                                     Address &dynamic_address)
50{
51    // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0
52    // in the object.  That will point to the "address point" within the vtable (not the beginning of the
53    // vtable.)  We can then look up the symbol containing this "address point" and that symbol's name
54    // demangled will contain the full class name.
55    // The second pointer above the "address point" is the "offset_to_top".  We'll use that to get the
56    // start of the value object which holds the dynamic type.
57    //
58
59    class_type_or_name.Clear();
60
61    // Only a pointer or reference type can have a different dynamic and static type:
62    if (CouldHaveDynamicValue (in_value))
63    {
64        // First job, pull out the address at 0 offset from the object.
65        AddressType address_type;
66        lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type);
67        if (original_ptr == LLDB_INVALID_ADDRESS)
68            return false;
69
70        ExecutionContext exe_ctx (in_value.GetExecutionContextRef());
71
72        Target *target = exe_ctx.GetTargetPtr();
73        Process *process = exe_ctx.GetProcessPtr();
74
75        char memory_buffer[16];
76        DataExtractor data(memory_buffer, sizeof(memory_buffer),
77                           process->GetByteOrder(),
78                           process->GetAddressByteSize());
79        size_t address_byte_size = process->GetAddressByteSize();
80        Error error;
81        size_t bytes_read = process->ReadMemory (original_ptr,
82                                                 memory_buffer,
83                                                 address_byte_size,
84                                                 error);
85        if (!error.Success() || (bytes_read != address_byte_size))
86        {
87            return false;
88        }
89
90        lldb::offset_t offset = 0;
91        lldb::addr_t vtable_address_point = data.GetAddress (&offset);
92
93        if (offset == 0)
94            return false;
95
96        // Now find the symbol that contains this address:
97
98        SymbolContext sc;
99        Address address_point_address;
100        if (target && !target->GetSectionLoadList().IsEmpty())
101        {
102            if (target->GetSectionLoadList().ResolveLoadAddress (vtable_address_point, address_point_address))
103            {
104                target->GetImages().ResolveSymbolContextForAddress (address_point_address, eSymbolContextSymbol, sc);
105                Symbol *symbol = sc.symbol;
106                if (symbol != NULL)
107                {
108                    const char *name = symbol->GetMangled().GetDemangledName().AsCString();
109                    if (strstr(name, vtable_demangled_prefix) == name)
110                    {
111                        Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
112                        if (log)
113                            log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has vtable symbol '%s'\n",
114                                         original_ptr,
115                                         in_value.GetTypeName().GetCString(),
116                                         name);
117                        // We are a C++ class, that's good.  Get the class name and look it up:
118                        const char *class_name = name + strlen(vtable_demangled_prefix);
119                        class_type_or_name.SetName (class_name);
120                        const bool exact_match = true;
121                        TypeList class_types;
122
123                        uint32_t num_matches = 0;
124                        // First look in the module that the vtable symbol came from
125                        // and look for a single exact match.
126                        if (sc.module_sp)
127                        {
128                            num_matches = sc.module_sp->FindTypes (sc,
129                                                                   ConstString(class_name),
130                                                                   exact_match,
131                                                                   1,
132                                                                   class_types);
133                        }
134
135                        // If we didn't find a symbol, then move on to the entire
136                        // module list in the target and get as many unique matches
137                        // as possible
138                        if (num_matches == 0)
139                        {
140                            num_matches = target->GetImages().FindTypes (sc,
141                                                                         ConstString(class_name),
142                                                                         exact_match,
143                                                                         UINT32_MAX,
144                                                                         class_types);
145                        }
146
147                        lldb::TypeSP type_sp;
148                        if (num_matches == 0)
149                        {
150                            if (log)
151                                log->Printf("0x%16.16" PRIx64 ": is not dynamic\n", original_ptr);
152                            return false;
153                        }
154                        if (num_matches == 1)
155                        {
156                            type_sp = class_types.GetTypeAtIndex(0);
157                            if (log)
158                                log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 "}, type-name='%s'\n",
159                                             original_ptr,
160                                             in_value.GetTypeName().AsCString(),
161                                             type_sp->GetID(),
162                                             type_sp->GetName().GetCString());
163
164                            class_type_or_name.SetTypeSP(class_types.GetTypeAtIndex(0));
165                        }
166                        else if (num_matches > 1)
167                        {
168                            size_t i;
169                            if (log)
170                            {
171                                for (i = 0; i < num_matches; i++)
172                                {
173                                    type_sp = class_types.GetTypeAtIndex(i);
174                                    if (type_sp)
175                                    {
176                                        if (log)
177                                            log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types: uid={0x%" PRIx64 "}, type-name='%s'\n",
178                                                         original_ptr,
179                                                         in_value.GetTypeName().AsCString(),
180                                                         type_sp->GetID(),
181                                                         type_sp->GetName().GetCString());
182                                    }
183                                }
184                            }
185
186                            for (i = 0; i < num_matches; i++)
187                            {
188                                type_sp = class_types.GetTypeAtIndex(i);
189                                if (type_sp)
190                                {
191                                    if (type_sp->GetClangFullType().IsCXXClassType())
192                                    {
193                                        if (log)
194                                            log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, picking this one: uid={0x%" PRIx64 "}, type-name='%s'\n",
195                                                         original_ptr,
196                                                         in_value.GetTypeName().AsCString(),
197                                                         type_sp->GetID(),
198                                                         type_sp->GetName().GetCString());
199                                        class_type_or_name.SetTypeSP(type_sp);
200                                        break;
201                                    }
202                                }
203                            }
204
205                            if (i == num_matches)
206                            {
207                                if (log)
208                                    log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, didn't find a C++ match\n",
209                                                 original_ptr,
210                                                 in_value.GetTypeName().AsCString());
211                                return false;
212                            }
213                        }
214
215                        // There can only be one type with a given name,
216                        // so we've just found duplicate definitions, and this
217                        // one will do as well as any other.
218                        // We don't consider something to have a dynamic type if
219                        // it is the same as the static type.  So compare against
220                        // the value we were handed.
221                        if (type_sp)
222                        {
223                            if (ClangASTContext::AreTypesSame (in_value.GetClangType(),
224                                                               type_sp->GetClangFullType()))
225                            {
226                                // The dynamic type we found was the same type,
227                                // so we don't have a dynamic type here...
228                                return false;
229                            }
230
231                            // The offset_to_top is two pointers above the address.
232                            Address offset_to_top_address = address_point_address;
233                            int64_t slide = -2 * ((int64_t) target->GetArchitecture().GetAddressByteSize());
234                            offset_to_top_address.Slide (slide);
235
236                            Error error;
237                            lldb::addr_t offset_to_top_location = offset_to_top_address.GetLoadAddress(target);
238
239                            size_t bytes_read = process->ReadMemory (offset_to_top_location,
240                                                                     memory_buffer,
241                                                                     address_byte_size,
242                                                                     error);
243
244                            if (!error.Success() || (bytes_read != address_byte_size))
245                            {
246                                return false;
247                            }
248
249                            offset = 0;
250                            int64_t offset_to_top = data.GetMaxS64(&offset, process->GetAddressByteSize());
251
252                            // So the dynamic type is a value that starts at offset_to_top
253                            // above the original address.
254                            lldb::addr_t dynamic_addr = original_ptr + offset_to_top;
255                            if (!target->GetSectionLoadList().ResolveLoadAddress (dynamic_addr, dynamic_address))
256                            {
257                                dynamic_address.SetRawAddress(dynamic_addr);
258                            }
259                            return true;
260                        }
261                    }
262                }
263            }
264        }
265    }
266
267    return class_type_or_name.IsEmpty() == false;
268}
269
270bool
271ItaniumABILanguageRuntime::IsVTableName (const char *name)
272{
273    if (name == NULL)
274        return false;
275
276    // Can we maybe ask Clang about this?
277    if (strstr (name, "_vptr$") == name)
278        return true;
279    else
280        return false;
281}
282
283//------------------------------------------------------------------
284// Static Functions
285//------------------------------------------------------------------
286LanguageRuntime *
287ItaniumABILanguageRuntime::CreateInstance (Process *process, lldb::LanguageType language)
288{
289    // FIXME: We have to check the process and make sure we actually know that this process supports
290    // the Itanium ABI.
291    if (language == eLanguageTypeC_plus_plus)
292        return new ItaniumABILanguageRuntime (process);
293    else
294        return NULL;
295}
296
297void
298ItaniumABILanguageRuntime::Initialize()
299{
300    PluginManager::RegisterPlugin (GetPluginNameStatic(),
301                                   "Itanium ABI for the C++ language",
302                                   CreateInstance);
303}
304
305void
306ItaniumABILanguageRuntime::Terminate()
307{
308    PluginManager::UnregisterPlugin (CreateInstance);
309}
310
311lldb_private::ConstString
312ItaniumABILanguageRuntime::GetPluginNameStatic()
313{
314    static ConstString g_name("itanium");
315    return g_name;
316}
317
318//------------------------------------------------------------------
319// PluginInterface protocol
320//------------------------------------------------------------------
321lldb_private::ConstString
322ItaniumABILanguageRuntime::GetPluginName()
323{
324    return GetPluginNameStatic();
325}
326
327uint32_t
328ItaniumABILanguageRuntime::GetPluginVersion()
329{
330    return 1;
331}
332
333BreakpointResolverSP
334ItaniumABILanguageRuntime::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp)
335{
336    return CreateExceptionResolver (bkpt, catch_bp, throw_bp, false);
337}
338
339BreakpointResolverSP
340ItaniumABILanguageRuntime::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp, bool for_expressions)
341{
342    // One complication here is that most users DON'T want to stop at __cxa_allocate_expression, but until we can do
343    // anything better with predicting unwinding the expression parser does.  So we have two forms of the exception
344    // breakpoints, one for expressions that leaves out __cxa_allocate_exception, and one that includes it.
345    // The SetExceptionBreakpoints does the latter, the CreateExceptionBreakpoint in the runtime the former.
346    static const char *g_catch_name = "__cxa_begin_catch";
347    static const char *g_throw_name1 = "__cxa_throw";
348    static const char *g_throw_name2 = "__cxa_rethrow";
349    static const char *g_exception_throw_name = "__cxa_allocate_exception";
350    std::vector<const char *> exception_names;
351    exception_names.reserve(4);
352    if (catch_bp)
353        exception_names.push_back(g_catch_name);
354
355    if (throw_bp)
356    {
357        exception_names.push_back(g_throw_name1);
358        exception_names.push_back(g_throw_name2);
359    }
360
361    if (for_expressions)
362        exception_names.push_back(g_exception_throw_name);
363
364    BreakpointResolverSP resolver_sp (new BreakpointResolverName (bkpt,
365                                                                  exception_names.data(),
366                                                                  exception_names.size(),
367                                                                  eFunctionNameTypeBase,
368                                                                  eLazyBoolNo));
369
370    return resolver_sp;
371}
372
373
374
375lldb::SearchFilterSP
376ItaniumABILanguageRuntime::CreateExceptionSearchFilter ()
377{
378    Target &target = m_process->GetTarget();
379
380    if (target.GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple)
381    {
382        // Limit the number of modules that are searched for these breakpoints for
383        // Apple binaries.
384        FileSpecList filter_modules;
385        filter_modules.Append(FileSpec("libc++abi.dylib", false));
386        filter_modules.Append(FileSpec("libSystem.B.dylib", false));
387        return target.GetSearchFilterForModuleList(&filter_modules);
388    }
389    else
390    {
391        return LanguageRuntime::CreateExceptionSearchFilter();
392    }
393}
394
395lldb::BreakpointSP
396ItaniumABILanguageRuntime::CreateExceptionBreakpoint (bool catch_bp,
397                                                      bool throw_bp,
398                                                      bool for_expressions,
399                                                      bool is_internal)
400{
401    Target &target = m_process->GetTarget();
402    FileSpecList filter_modules;
403    BreakpointResolverSP exception_resolver_sp = CreateExceptionResolver (NULL, catch_bp, throw_bp, for_expressions);
404    SearchFilterSP filter_sp (CreateExceptionSearchFilter ());
405    return target.CreateBreakpoint (filter_sp, exception_resolver_sp, is_internal);
406}
407
408void
409ItaniumABILanguageRuntime::SetExceptionBreakpoints ()
410{
411    if (!m_process)
412        return;
413
414    const bool catch_bp = false;
415    const bool throw_bp = true;
416    const bool is_internal = true;
417    const bool for_expressions = true;
418
419    // For the exception breakpoints set by the Expression parser, we'll be a little more aggressive and
420    // stop at exception allocation as well.
421
422    if (m_cxx_exception_bp_sp)
423    {
424        m_cxx_exception_bp_sp->SetEnabled (true);
425    }
426    else
427    {
428        m_cxx_exception_bp_sp = CreateExceptionBreakpoint (catch_bp, throw_bp, for_expressions, is_internal);
429        if (m_cxx_exception_bp_sp)
430            m_cxx_exception_bp_sp->SetBreakpointKind("c++ exception");
431    }
432
433}
434
435void
436ItaniumABILanguageRuntime::ClearExceptionBreakpoints ()
437{
438    if (!m_process)
439        return;
440
441    if (m_cxx_exception_bp_sp)
442    {
443        m_cxx_exception_bp_sp->SetEnabled (false);
444    }
445}
446
447bool
448ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason)
449{
450    if (!m_process)
451        return false;
452
453    if (!stop_reason ||
454        stop_reason->GetStopReason() != eStopReasonBreakpoint)
455        return false;
456
457    uint64_t break_site_id = stop_reason->GetValue();
458    return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint(break_site_id,
459                                                                               m_cxx_exception_bp_sp->GetID());
460
461}
462