• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *vtable_demangled_prefix = "vtable for ";
36 
37 bool
CouldHaveDynamicValue(ValueObject & in_value)38 ItaniumABILanguageRuntime::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 
45 bool
GetDynamicTypeAndAddress(ValueObject & in_value,lldb::DynamicValueType use_dynamic,TypeAndOrName & class_type_or_name,Address & dynamic_address)46 ItaniumABILanguageRuntime::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 
270 bool
IsVTableName(const char * name)271 ItaniumABILanguageRuntime::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 //------------------------------------------------------------------
286 LanguageRuntime *
CreateInstance(Process * process,lldb::LanguageType language)287 ItaniumABILanguageRuntime::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 
297 void
Initialize()298 ItaniumABILanguageRuntime::Initialize()
299 {
300     PluginManager::RegisterPlugin (GetPluginNameStatic(),
301                                    "Itanium ABI for the C++ language",
302                                    CreateInstance);
303 }
304 
305 void
Terminate()306 ItaniumABILanguageRuntime::Terminate()
307 {
308     PluginManager::UnregisterPlugin (CreateInstance);
309 }
310 
311 lldb_private::ConstString
GetPluginNameStatic()312 ItaniumABILanguageRuntime::GetPluginNameStatic()
313 {
314     static ConstString g_name("itanium");
315     return g_name;
316 }
317 
318 //------------------------------------------------------------------
319 // PluginInterface protocol
320 //------------------------------------------------------------------
321 lldb_private::ConstString
GetPluginName()322 ItaniumABILanguageRuntime::GetPluginName()
323 {
324     return GetPluginNameStatic();
325 }
326 
327 uint32_t
GetPluginVersion()328 ItaniumABILanguageRuntime::GetPluginVersion()
329 {
330     return 1;
331 }
332 
333 BreakpointResolverSP
CreateExceptionResolver(Breakpoint * bkpt,bool catch_bp,bool throw_bp)334 ItaniumABILanguageRuntime::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp)
335 {
336     return CreateExceptionResolver (bkpt, catch_bp, throw_bp, false);
337 }
338 
339 BreakpointResolverSP
CreateExceptionResolver(Breakpoint * bkpt,bool catch_bp,bool throw_bp,bool for_expressions)340 ItaniumABILanguageRuntime::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 
375 lldb::SearchFilterSP
CreateExceptionSearchFilter()376 ItaniumABILanguageRuntime::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 
395 lldb::BreakpointSP
CreateExceptionBreakpoint(bool catch_bp,bool throw_bp,bool for_expressions,bool is_internal)396 ItaniumABILanguageRuntime::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 
408 void
SetExceptionBreakpoints()409 ItaniumABILanguageRuntime::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 
435 void
ClearExceptionBreakpoints()436 ItaniumABILanguageRuntime::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 
447 bool
ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason)448 ItaniumABILanguageRuntime::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