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