ItaniumABILanguageRuntime.cpp revision 263367
1210312Sjmallett//===-- ItaniumABILanguageRuntime.cpp --------------------------------------*- C++ -*-===// 2210312Sjmallett// 3210312Sjmallett// The LLVM Compiler Infrastructure 4210312Sjmallett// 5210312Sjmallett// This file is distributed under the University of Illinois Open Source 6210312Sjmallett// License. See LICENSE.TXT for details. 7210312Sjmallett// 8210312Sjmallett//===----------------------------------------------------------------------===// 9210312Sjmallett 10210312Sjmallett#include "ItaniumABILanguageRuntime.h" 11210312Sjmallett 12210312Sjmallett#include "lldb/Breakpoint/BreakpointLocation.h" 13210312Sjmallett#include "lldb/Core/ConstString.h" 14210312Sjmallett#include "lldb/Core/Error.h" 15210312Sjmallett#include "lldb/Core/Log.h" 16210312Sjmallett#include "lldb/Core/Module.h" 17210312Sjmallett#include "lldb/Core/PluginManager.h" 18210312Sjmallett#include "lldb/Core/Scalar.h" 19210312Sjmallett#include "lldb/Core/ValueObject.h" 20210312Sjmallett#include "lldb/Core/ValueObjectMemory.h" 21210312Sjmallett#include "lldb/Symbol/ClangASTContext.h" 22210312Sjmallett#include "lldb/Symbol/Symbol.h" 23210312Sjmallett#include "lldb/Symbol/TypeList.h" 24210312Sjmallett#include "lldb/Target/Process.h" 25210312Sjmallett#include "lldb/Target/RegisterContext.h" 26210312Sjmallett#include "lldb/Target/StopInfo.h" 27210312Sjmallett#include "lldb/Target/Target.h" 28210312Sjmallett#include "lldb/Target/Thread.h" 29210312Sjmallett 30210312Sjmallett#include <vector> 31210312Sjmallett 32210312Sjmallettusing namespace lldb; 33210312Sjmallettusing namespace lldb_private; 34210312Sjmallett 35210312Sjmallettstatic const char *vtable_demangled_prefix = "vtable for "; 36210312Sjmallett 37210312Sjmallettbool 38210312SjmallettItaniumABILanguageRuntime::CouldHaveDynamicValue (ValueObject &in_value) 39210312Sjmallett{ 40210312Sjmallett const bool check_cxx = true; 41210312Sjmallett const bool check_objc = false; 42210312Sjmallett return in_value.GetClangType().IsPossibleDynamicType (NULL, check_cxx, check_objc); 43210312Sjmallett} 44210312Sjmallett 45210312Sjmallettbool 46210312SjmallettItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value, 47210312Sjmallett lldb::DynamicValueType use_dynamic, 48210312Sjmallett TypeAndOrName &class_type_or_name, 49210312Sjmallett Address &dynamic_address) 50210312Sjmallett{ 51210312Sjmallett // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0 52210312Sjmallett // in the object. That will point to the "address point" within the vtable (not the beginning of the 53210312Sjmallett // vtable.) We can then look up the symbol containing this "address point" and that symbol's name 54210312Sjmallett // demangled will contain the full class name. 55210312Sjmallett // The second pointer above the "address point" is the "offset_to_top". We'll use that to get the 56210312Sjmallett // start of the value object which holds the dynamic type. 57210312Sjmallett // 58210312Sjmallett 59210312Sjmallett class_type_or_name.Clear(); 60210312Sjmallett 61210312Sjmallett // Only a pointer or reference type can have a different dynamic and static type: 62210312Sjmallett if (CouldHaveDynamicValue (in_value)) 63210312Sjmallett { 64210312Sjmallett // First job, pull out the address at 0 offset from the object. 65210312Sjmallett AddressType address_type; 66210312Sjmallett lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type); 67210312Sjmallett if (original_ptr == LLDB_INVALID_ADDRESS) 68210312Sjmallett return false; 69210312Sjmallett 70210312Sjmallett ExecutionContext exe_ctx (in_value.GetExecutionContextRef()); 71210312Sjmallett 72210312Sjmallett Target *target = exe_ctx.GetTargetPtr(); 73210312Sjmallett Process *process = exe_ctx.GetProcessPtr(); 74210312Sjmallett 75210312Sjmallett char memory_buffer[16]; 76210312Sjmallett DataExtractor data(memory_buffer, sizeof(memory_buffer), 77210312Sjmallett process->GetByteOrder(), 78210312Sjmallett process->GetAddressByteSize()); 79210312Sjmallett size_t address_byte_size = process->GetAddressByteSize(); 80210312Sjmallett Error error; 81210312Sjmallett size_t bytes_read = process->ReadMemory (original_ptr, 82210312Sjmallett memory_buffer, 83210312Sjmallett address_byte_size, 84210312Sjmallett error); 85210312Sjmallett if (!error.Success() || (bytes_read != address_byte_size)) 86210312Sjmallett { 87210312Sjmallett return false; 88210312Sjmallett } 89210312Sjmallett 90210312Sjmallett lldb::offset_t offset = 0; 91210312Sjmallett lldb::addr_t vtable_address_point = data.GetAddress (&offset); 92210312Sjmallett 93210312Sjmallett if (offset == 0) 94210312Sjmallett return false; 95210312Sjmallett 96210312Sjmallett // Now find the symbol that contains this address: 97210312Sjmallett 98210312Sjmallett SymbolContext sc; 99210312Sjmallett Address address_point_address; 100210312Sjmallett if (target && !target->GetSectionLoadList().IsEmpty()) 101210312Sjmallett { 102210312Sjmallett if (target->GetSectionLoadList().ResolveLoadAddress (vtable_address_point, address_point_address)) 103210312Sjmallett { 104210312Sjmallett target->GetImages().ResolveSymbolContextForAddress (address_point_address, eSymbolContextSymbol, sc); 105210312Sjmallett Symbol *symbol = sc.symbol; 106210312Sjmallett if (symbol != NULL) 107210312Sjmallett { 108210312Sjmallett const char *name = symbol->GetMangled().GetDemangledName().AsCString(); 109210312Sjmallett if (strstr(name, vtable_demangled_prefix) == name) 110210312Sjmallett { 111210312Sjmallett Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); 112210312Sjmallett if (log) 113210312Sjmallett log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has vtable symbol '%s'\n", 114210312Sjmallett original_ptr, 115210312Sjmallett in_value.GetTypeName().GetCString(), 116210312Sjmallett name); 117210312Sjmallett // We are a C++ class, that's good. Get the class name and look it up: 118210312Sjmallett const char *class_name = name + strlen(vtable_demangled_prefix); 119210312Sjmallett class_type_or_name.SetName (class_name); 120210312Sjmallett const bool exact_match = true; 121210312Sjmallett TypeList class_types; 122210312Sjmallett 123210312Sjmallett uint32_t num_matches = 0; 124210312Sjmallett // First look in the module that the vtable symbol came from 125210312Sjmallett // and look for a single exact match. 126210312Sjmallett if (sc.module_sp) 127210312Sjmallett { 128210312Sjmallett num_matches = sc.module_sp->FindTypes (sc, 129210312Sjmallett ConstString(class_name), 130210312Sjmallett exact_match, 131210312Sjmallett 1, 132210312Sjmallett class_types); 133210312Sjmallett } 134210312Sjmallett 135210312Sjmallett // If we didn't find a symbol, then move on to the entire 136210312Sjmallett // module list in the target and get as many unique matches 137210312Sjmallett // as possible 138210312Sjmallett if (num_matches == 0) 139210312Sjmallett { 140210312Sjmallett num_matches = target->GetImages().FindTypes (sc, 141210312Sjmallett ConstString(class_name), 142210312Sjmallett exact_match, 143210312Sjmallett UINT32_MAX, 144210312Sjmallett class_types); 145210312Sjmallett } 146210312Sjmallett 147210312Sjmallett lldb::TypeSP type_sp; 148210312Sjmallett if (num_matches == 0) 149210312Sjmallett { 150210312Sjmallett if (log) 151210312Sjmallett log->Printf("0x%16.16" PRIx64 ": is not dynamic\n", original_ptr); 152210312Sjmallett return false; 153210312Sjmallett } 154210312Sjmallett if (num_matches == 1) 155210312Sjmallett { 156210312Sjmallett type_sp = class_types.GetTypeAtIndex(0); 157210312Sjmallett if (log) 158210312Sjmallett log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 "}, type-name='%s'\n", 159210312Sjmallett original_ptr, 160210312Sjmallett in_value.GetTypeName().AsCString(), 161210312Sjmallett type_sp->GetID(), 162210312Sjmallett type_sp->GetName().GetCString()); 163210312Sjmallett 164210312Sjmallett class_type_or_name.SetTypeSP(class_types.GetTypeAtIndex(0)); 165210312Sjmallett } 166210312Sjmallett else if (num_matches > 1) 167210312Sjmallett { 168210312Sjmallett size_t i; 169210312Sjmallett if (log) 170210312Sjmallett { 171210312Sjmallett for (i = 0; i < num_matches; i++) 172210312Sjmallett { 173210312Sjmallett type_sp = class_types.GetTypeAtIndex(i); 174210312Sjmallett if (type_sp) 175210312Sjmallett { 176210312Sjmallett if (log) 177210312Sjmallett log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types: uid={0x%" PRIx64 "}, type-name='%s'\n", 178210312Sjmallett original_ptr, 179210312Sjmallett in_value.GetTypeName().AsCString(), 180210312Sjmallett type_sp->GetID(), 181210312Sjmallett type_sp->GetName().GetCString()); 182210312Sjmallett } 183210312Sjmallett } 184210312Sjmallett } 185210312Sjmallett 186210312Sjmallett for (i = 0; i < num_matches; i++) 187210312Sjmallett { 188210312Sjmallett type_sp = class_types.GetTypeAtIndex(i); 189210312Sjmallett if (type_sp) 190210312Sjmallett { 191210312Sjmallett if (type_sp->GetClangFullType().IsCXXClassType()) 192210312Sjmallett { 193210312Sjmallett if (log) 194210312Sjmallett log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, picking this one: uid={0x%" PRIx64 "}, type-name='%s'\n", 195210312Sjmallett original_ptr, 196210312Sjmallett in_value.GetTypeName().AsCString(), 197210312Sjmallett type_sp->GetID(), 198210312Sjmallett type_sp->GetName().GetCString()); 199210312Sjmallett class_type_or_name.SetTypeSP(type_sp); 200210312Sjmallett break; 201210312Sjmallett } 202210312Sjmallett } 203210312Sjmallett } 204210312Sjmallett 205210312Sjmallett if (i == num_matches) 206210312Sjmallett { 207210312Sjmallett if (log) 208210312Sjmallett log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, didn't find a C++ match\n", 209210312Sjmallett original_ptr, 210210312Sjmallett in_value.GetTypeName().AsCString()); 211210312Sjmallett return false; 212210312Sjmallett } 213210312Sjmallett } 214210312Sjmallett 215210312Sjmallett // There can only be one type with a given name, 216210312Sjmallett // so we've just found duplicate definitions, and this 217210312Sjmallett // one will do as well as any other. 218210312Sjmallett // We don't consider something to have a dynamic type if 219210312Sjmallett // it is the same as the static type. So compare against 220210312Sjmallett // the value we were handed. 221210312Sjmallett if (type_sp) 222210312Sjmallett { 223210312Sjmallett if (ClangASTContext::AreTypesSame (in_value.GetClangType(), 224210312Sjmallett type_sp->GetClangFullType())) 225210312Sjmallett { 226210312Sjmallett // The dynamic type we found was the same type, 227210312Sjmallett // so we don't have a dynamic type here... 228210312Sjmallett return false; 229210312Sjmallett } 230210312Sjmallett 231210312Sjmallett // The offset_to_top is two pointers above the address. 232210312Sjmallett Address offset_to_top_address = address_point_address; 233210312Sjmallett int64_t slide = -2 * ((int64_t) target->GetArchitecture().GetAddressByteSize()); 234210312Sjmallett offset_to_top_address.Slide (slide); 235210312Sjmallett 236210312Sjmallett Error error; 237210312Sjmallett lldb::addr_t offset_to_top_location = offset_to_top_address.GetLoadAddress(target); 238210312Sjmallett 239210312Sjmallett size_t bytes_read = process->ReadMemory (offset_to_top_location, 240210312Sjmallett memory_buffer, 241210312Sjmallett address_byte_size, 242210312Sjmallett error); 243210312Sjmallett 244210312Sjmallett if (!error.Success() || (bytes_read != address_byte_size)) 245210312Sjmallett { 246210312Sjmallett return false; 247210312Sjmallett } 248210312Sjmallett 249210312Sjmallett offset = 0; 250210312Sjmallett int64_t offset_to_top = data.GetMaxS64(&offset, process->GetAddressByteSize()); 251210312Sjmallett 252210312Sjmallett // So the dynamic type is a value that starts at offset_to_top 253210312Sjmallett // above the original address. 254210312Sjmallett lldb::addr_t dynamic_addr = original_ptr + offset_to_top; 255210312Sjmallett if (!target->GetSectionLoadList().ResolveLoadAddress (dynamic_addr, dynamic_address)) 256210312Sjmallett { 257210312Sjmallett dynamic_address.SetRawAddress(dynamic_addr); 258210312Sjmallett } 259210312Sjmallett return true; 260210312Sjmallett } 261210312Sjmallett } 262210312Sjmallett } 263210312Sjmallett } 264210312Sjmallett } 265210312Sjmallett } 266210312Sjmallett 267210312Sjmallett return class_type_or_name.IsEmpty() == false; 268210312Sjmallett} 269210312Sjmallett 270210312Sjmallettbool 271210312SjmallettItaniumABILanguageRuntime::IsVTableName (const char *name) 272210312Sjmallett{ 273210312Sjmallett if (name == NULL) 274210312Sjmallett return false; 275210312Sjmallett 276210312Sjmallett // Can we maybe ask Clang about this? 277210312Sjmallett if (strstr (name, "_vptr$") == name) 278210312Sjmallett return true; 279210312Sjmallett else 280210312Sjmallett return false; 281210312Sjmallett} 282210312Sjmallett 283210312Sjmallett//------------------------------------------------------------------ 284210312Sjmallett// Static Functions 285210312Sjmallett//------------------------------------------------------------------ 286210312SjmallettLanguageRuntime * 287210312SjmallettItaniumABILanguageRuntime::CreateInstance (Process *process, lldb::LanguageType language) 288210312Sjmallett{ 289210312Sjmallett // FIXME: We have to check the process and make sure we actually know that this process supports 290210312Sjmallett // the Itanium ABI. 291210312Sjmallett if (language == eLanguageTypeC_plus_plus) 292210312Sjmallett return new ItaniumABILanguageRuntime (process); 293210312Sjmallett else 294210312Sjmallett return NULL; 295210312Sjmallett} 296210312Sjmallett 297210312Sjmallettvoid 298210312SjmallettItaniumABILanguageRuntime::Initialize() 299210312Sjmallett{ 300210312Sjmallett PluginManager::RegisterPlugin (GetPluginNameStatic(), 301210312Sjmallett "Itanium ABI for the C++ language", 302210312Sjmallett CreateInstance); 303210312Sjmallett} 304210312Sjmallett 305210312Sjmallettvoid 306210312SjmallettItaniumABILanguageRuntime::Terminate() 307210312Sjmallett{ 308210312Sjmallett PluginManager::UnregisterPlugin (CreateInstance); 309210312Sjmallett} 310210312Sjmallett 311210312Sjmallettlldb_private::ConstString 312210312SjmallettItaniumABILanguageRuntime::GetPluginNameStatic() 313210312Sjmallett{ 314210312Sjmallett static ConstString g_name("itanium"); 315210312Sjmallett return g_name; 316210312Sjmallett} 317210312Sjmallett 318210312Sjmallett//------------------------------------------------------------------ 319210312Sjmallett// PluginInterface protocol 320210312Sjmallett//------------------------------------------------------------------ 321210312Sjmallettlldb_private::ConstString 322210312SjmallettItaniumABILanguageRuntime::GetPluginName() 323210312Sjmallett{ 324210312Sjmallett return GetPluginNameStatic(); 325210312Sjmallett} 326210312Sjmallett 327210312Sjmallettuint32_t 328210312SjmallettItaniumABILanguageRuntime::GetPluginVersion() 329210312Sjmallett{ 330210312Sjmallett return 1; 331210312Sjmallett} 332210312Sjmallett 333210312SjmallettBreakpointResolverSP 334210312SjmallettItaniumABILanguageRuntime::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp) 335210312Sjmallett{ 336210312Sjmallett return CreateExceptionResolver (bkpt, catch_bp, throw_bp, false); 337210312Sjmallett} 338217620Sgonzo 339210312SjmallettBreakpointResolverSP 340210312SjmallettItaniumABILanguageRuntime::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp, bool for_expressions) 341210312Sjmallett{ 342210312Sjmallett // One complication here is that most users DON'T want to stop at __cxa_allocate_expression, but until we can do 343210312Sjmallett // anything better with predicting unwinding the expression parser does. So we have two forms of the exception 344210312Sjmallett // breakpoints, one for expressions that leaves out __cxa_allocate_exception, and one that includes it. 345210312Sjmallett // The SetExceptionBreakpoints does the latter, the CreateExceptionBreakpoint in the runtime the former. 346210312Sjmallett static const char *g_catch_name = "__cxa_begin_catch"; 347210312Sjmallett static const char *g_throw_name1 = "__cxa_throw"; 348210312Sjmallett static const char *g_throw_name2 = "__cxa_rethrow"; 349210312Sjmallett static const char *g_exception_throw_name = "__cxa_allocate_exception"; 350210312Sjmallett std::vector<const char *> exception_names; 351210312Sjmallett exception_names.reserve(4); 352210312Sjmallett if (catch_bp) 353210312Sjmallett exception_names.push_back(g_catch_name); 354210312Sjmallett 355210312Sjmallett if (throw_bp) 356210312Sjmallett { 357210312Sjmallett exception_names.push_back(g_throw_name1); 358210312Sjmallett exception_names.push_back(g_throw_name2); 359210312Sjmallett } 360210312Sjmallett 361210312Sjmallett if (for_expressions) 362210312Sjmallett exception_names.push_back(g_exception_throw_name); 363210312Sjmallett 364210312Sjmallett BreakpointResolverSP resolver_sp (new BreakpointResolverName (bkpt, 365210312Sjmallett exception_names.data(), 366210312Sjmallett exception_names.size(), 367210312Sjmallett eFunctionNameTypeBase, 368210312Sjmallett eLazyBoolNo)); 369210312Sjmallett 370210312Sjmallett return resolver_sp; 371210312Sjmallett} 372210312Sjmallett 373210312Sjmallett 374210312Sjmallett 375210312Sjmallettlldb::SearchFilterSP 376210312SjmallettItaniumABILanguageRuntime::CreateExceptionSearchFilter () 377210312Sjmallett{ 378210312Sjmallett Target &target = m_process->GetTarget(); 379210312Sjmallett 380210312Sjmallett if (target.GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple) 381210312Sjmallett { 382210312Sjmallett // Limit the number of modules that are searched for these breakpoints for 383210312Sjmallett // Apple binaries. 384210312Sjmallett FileSpecList filter_modules; 385210312Sjmallett filter_modules.Append(FileSpec("libc++abi.dylib", false)); 386210312Sjmallett filter_modules.Append(FileSpec("libSystem.B.dylib", false)); 387210312Sjmallett return target.GetSearchFilterForModuleList(&filter_modules); 388210312Sjmallett } 389210312Sjmallett else 390210312Sjmallett { 391210312Sjmallett return LanguageRuntime::CreateExceptionSearchFilter(); 392210312Sjmallett } 393210312Sjmallett} 394210312Sjmallett 395210312Sjmallettlldb::BreakpointSP 396210312SjmallettItaniumABILanguageRuntime::CreateExceptionBreakpoint (bool catch_bp, 397217620Sgonzo bool throw_bp, 398210312Sjmallett bool for_expressions, 399210312Sjmallett bool is_internal) 400210312Sjmallett{ 401210312Sjmallett Target &target = m_process->GetTarget(); 402210312Sjmallett FileSpecList filter_modules; 403210312Sjmallett BreakpointResolverSP exception_resolver_sp = CreateExceptionResolver (NULL, catch_bp, throw_bp, for_expressions); 404210312Sjmallett SearchFilterSP filter_sp (CreateExceptionSearchFilter ()); 405210312Sjmallett return target.CreateBreakpoint (filter_sp, exception_resolver_sp, is_internal, false); 406210312Sjmallett} 407210312Sjmallett 408210312Sjmallettvoid 409210312SjmallettItaniumABILanguageRuntime::SetExceptionBreakpoints () 410210312Sjmallett{ 411210312Sjmallett if (!m_process) 412210312Sjmallett return; 413210312Sjmallett 414210312Sjmallett const bool catch_bp = false; 415210312Sjmallett const bool throw_bp = true; 416210312Sjmallett const bool is_internal = true; 417210312Sjmallett const bool for_expressions = true; 418210312Sjmallett 419210312Sjmallett // For the exception breakpoints set by the Expression parser, we'll be a little more aggressive and 420210312Sjmallett // stop at exception allocation as well. 421210312Sjmallett 422210312Sjmallett if (m_cxx_exception_bp_sp) 423210312Sjmallett { 424210312Sjmallett m_cxx_exception_bp_sp->SetEnabled (true); 425210312Sjmallett } 426210312Sjmallett else 427210312Sjmallett { 428210312Sjmallett m_cxx_exception_bp_sp = CreateExceptionBreakpoint (catch_bp, throw_bp, for_expressions, is_internal); 429210312Sjmallett if (m_cxx_exception_bp_sp) 430210312Sjmallett m_cxx_exception_bp_sp->SetBreakpointKind("c++ exception"); 431210312Sjmallett } 432210312Sjmallett 433210312Sjmallett} 434210312Sjmallett 435210312Sjmallettvoid 436210312SjmallettItaniumABILanguageRuntime::ClearExceptionBreakpoints () 437210312Sjmallett{ 438210312Sjmallett if (!m_process) 439210312Sjmallett return; 440210312Sjmallett 441210312Sjmallett if (m_cxx_exception_bp_sp) 442210312Sjmallett { 443210312Sjmallett m_cxx_exception_bp_sp->SetEnabled (false); 444210312Sjmallett } 445210312Sjmallett} 446210312Sjmallett 447210312Sjmallettbool 448210312SjmallettItaniumABILanguageRuntime::ExceptionBreakpointsAreSet () 449210312Sjmallett{ 450210312Sjmallett return m_cxx_exception_bp_sp && m_cxx_exception_bp_sp->IsEnabled(); 451210312Sjmallett} 452210312Sjmallett 453210312Sjmallettbool 454210312SjmallettItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason) 455210312Sjmallett{ 456210312Sjmallett if (!m_process) 457217620Sgonzo return false; 458210312Sjmallett 459210312Sjmallett if (!stop_reason || 460210312Sjmallett stop_reason->GetStopReason() != eStopReasonBreakpoint) 461210312Sjmallett return false; 462210312Sjmallett 463210312Sjmallett uint64_t break_site_id = stop_reason->GetValue(); 464210312Sjmallett return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint(break_site_id, 465210312Sjmallett m_cxx_exception_bp_sp->GetID()); 466210312Sjmallett 467210312Sjmallett} 468210312Sjmallett