bool ValueObjectRegister::UpdateValue() { m_error.Clear(); ExecutionContext exe_ctx(GetExecutionContextRef()); StackFrame *frame = exe_ctx.GetFramePtr(); if (frame == NULL) { m_reg_ctx_sp.reset(); m_reg_value.Clear(); } if (m_reg_ctx_sp) { RegisterValue m_old_reg_value(m_reg_value); if (m_reg_ctx_sp->ReadRegister(&m_reg_info, m_reg_value)) { if (m_reg_value.GetData(m_data)) { Process *process = exe_ctx.GetProcessPtr(); if (process) m_data.SetAddressByteSize(process->GetAddressByteSize()); m_value.SetContext(Value::eContextTypeRegisterInfo, (void *)&m_reg_info); m_value.SetValueType(Value::eValueTypeHostAddress); m_value.GetScalar() = (uintptr_t)m_data.GetDataStart(); SetValueIsValid(true); SetValueDidChange(!(m_old_reg_value == m_reg_value)); return true; } } } SetValueIsValid(false); m_error.SetErrorToGenericError(); return false; }
// this code relies on the assumption that an Objective-C object always starts // with an ISA at offset 0. ObjCLanguageRuntime::ObjCISA AppleObjCRuntimeV1::GetISA(ValueObject& valobj) { if (ClangASTType::GetMinimumLanguage(valobj.GetClangAST(),valobj.GetClangType()) != eLanguageTypeObjC) return 0; // if we get an invalid VO (which might still happen when playing around // with pointers returned by the expression parser, don't consider this // a valid ObjC object) if (valobj.GetValue().GetContextType() == Value::eContextTypeInvalid) return 0; addr_t isa_pointer = valobj.GetPointerValue(); ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); Process *process = exe_ctx.GetProcessPtr(); if (process) { uint8_t pointer_size = process->GetAddressByteSize(); Error error; return process->ReadUnsignedIntegerFromMemory (isa_pointer, pointer_size, 0, error); } return 0; }
bool DumpRegister(const ExecutionContext &exe_ctx, Stream &strm, RegisterContext *reg_ctx, const RegisterInfo *reg_info) { if (reg_info) { RegisterValue reg_value; if (reg_ctx->ReadRegister(reg_info, reg_value)) { strm.Indent(); bool prefix_with_altname = (bool)m_command_options.alternate_name; bool prefix_with_name = !prefix_with_altname; reg_value.Dump(&strm, reg_info, prefix_with_name, prefix_with_altname, m_format_options.GetFormat(), 8); if ((reg_info->encoding == eEncodingUint) || (reg_info->encoding == eEncodingSint)) { Process *process = exe_ctx.GetProcessPtr(); if (process && reg_info->byte_size == process->GetAddressByteSize()) { addr_t reg_addr = reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS); if (reg_addr != LLDB_INVALID_ADDRESS) { Address so_reg_addr; if (exe_ctx.GetTargetRef() .GetSectionLoadList() .ResolveLoadAddress(reg_addr, so_reg_addr)) { strm.PutCString(" "); so_reg_addr.Dump(&strm, exe_ctx.GetBestExecutionContextScope(), Address::DumpStyleResolvedDescription); } } } } strm.EOL(); return true; } } return false; }
bool ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Address function_address, ValueList &arg_values, Stream &errors) { // All the information to reconstruct the struct is provided by the // StructExtractor. if (!m_struct_valid) { errors.Printf("Argument information was not correctly parsed, so the function cannot be called."); return false; } Error error; using namespace clang; ExecutionResults return_value = eExecutionSetupError; Process *process = exe_ctx.GetProcessPtr(); if (process == NULL) return return_value; if (process != m_jit_process_sp.get()) return false; if (args_addr_ref == LLDB_INVALID_ADDRESS) { args_addr_ref = process->AllocateMemory(m_struct_size, lldb::ePermissionsReadable|lldb::ePermissionsWritable, error); if (args_addr_ref == LLDB_INVALID_ADDRESS) return false; m_wrapper_args_addrs.push_back (args_addr_ref); } else { // Make sure this is an address that we've already handed out. if (find (m_wrapper_args_addrs.begin(), m_wrapper_args_addrs.end(), args_addr_ref) == m_wrapper_args_addrs.end()) { return false; } } // TODO: verify fun_addr needs to be a callable address Scalar fun_addr (function_address.GetCallableLoadAddress(exe_ctx.GetTargetPtr())); int first_offset = m_member_offsets[0]; process->WriteScalarToMemory(args_addr_ref + first_offset, fun_addr, process->GetAddressByteSize(), error); // FIXME: We will need to extend this for Variadic functions. Error value_error; size_t num_args = arg_values.GetSize(); if (num_args != m_arg_values.GetSize()) { errors.Printf ("Wrong number of arguments - was: %lu should be: %lu", num_args, m_arg_values.GetSize()); return false; } for (size_t i = 0; i < num_args; i++) { // FIXME: We should sanity check sizes. int offset = m_member_offsets[i+1]; // Clang sizes are in bytes. Value *arg_value = arg_values.GetValueAtIndex(i); // FIXME: For now just do scalars: // Special case: if it's a pointer, don't do anything (the ABI supports passing cstrings) if (arg_value->GetValueType() == Value::eValueTypeHostAddress && arg_value->GetContextType() == Value::eContextTypeClangType && ClangASTContext::IsPointerType(arg_value->GetClangType())) continue; const Scalar &arg_scalar = arg_value->ResolveValue(&exe_ctx, m_clang_ast_context->getASTContext()); if (!process->WriteScalarToMemory(args_addr_ref + offset, arg_scalar, arg_scalar.GetByteSize(), error)) return false; } return true; }
ThreadPlanSP ObjCTrampolineHandler::GetStepThroughDispatchPlan (Thread &thread, bool stop_others) { ThreadPlanSP ret_plan_sp; lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC(); MsgsendMap::iterator pos; pos = m_msgSend_map.find (curr_pc); if (pos != m_msgSend_map.end()) { Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); const DispatchFunction *this_dispatch = &g_dispatch_functions[(*pos).second]; lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0); Process *process = thread.CalculateProcess(); const ABI *abi = process->GetABI(); if (abi == NULL) return ret_plan_sp; Target *target = thread.CalculateTarget(); // FIXME: Since neither the value nor the Clang QualType know their ASTContext, // we have to make sure the type we put in our value list comes from the same ASTContext // the ABI will use to get the argument values. THis is the bottom-most frame's module. ClangASTContext *clang_ast_context = target->GetScratchClangASTContext(); ValueList argument_values; Value input_value; void *clang_void_ptr_type = clang_ast_context->GetVoidPtrType(false); input_value.SetValueType (Value::eValueTypeScalar); input_value.SetContext (Value::eContextTypeOpaqueClangQualType, clang_void_ptr_type); int obj_index; int sel_index; // If this is a struct return dispatch, then the first argument is the // return struct pointer, and the object is the second, and the selector is the third. // Otherwise the object is the first and the selector the second. if (this_dispatch->stret_return) { obj_index = 1; sel_index = 2; argument_values.PushValue(input_value); argument_values.PushValue(input_value); argument_values.PushValue(input_value); } else { obj_index = 0; sel_index = 1; argument_values.PushValue(input_value); argument_values.PushValue(input_value); } bool success = abi->GetArgumentValues (thread, argument_values); if (!success) return ret_plan_sp; // Okay, the first value here is the object, we actually want the class of that object. // For now we're just going with the ISA. // FIXME: This should really be the return value of [object class] to properly handle KVO interposition. Value isa_value(*(argument_values.GetValueAtIndex(obj_index))); // This is a little cheesy, but since object->isa is the first field, // making the object value a load address value and resolving it will get // the pointer sized data pointed to by that value... ExecutionContext exec_ctx; thread.Calculate (exec_ctx); isa_value.SetValueType(Value::eValueTypeLoadAddress); isa_value.ResolveValue(&exec_ctx, clang_ast_context->getASTContext()); if (this_dispatch->fixedup == DispatchFunction::eFixUpFixed) { // For the FixedUp method the Selector is actually a pointer to a // structure, the second field of which is the selector number. Value *sel_value = argument_values.GetValueAtIndex(sel_index); sel_value->GetScalar() += process->GetAddressByteSize(); sel_value->SetValueType(Value::eValueTypeLoadAddress); sel_value->ResolveValue(&exec_ctx, clang_ast_context->getASTContext()); } else if (this_dispatch->fixedup == DispatchFunction::eFixUpToFix) { // FIXME: If the method dispatch is not "fixed up" then the selector is actually a // pointer to the string name of the selector. We need to look that up... // For now I'm going to punt on that and just return no plan. if (log) log->Printf ("Punting on stepping into un-fixed-up method dispatch."); return ret_plan_sp; } // FIXME: If this is a dispatch to the super-class, we need to get the super-class from // the class, and disaptch to that instead. // But for now I just punt and return no plan. if (this_dispatch->is_super) { if (log) log->Printf ("Punting on stepping into super method dispatch."); return ret_plan_sp; } ValueList dispatch_values; dispatch_values.PushValue (isa_value); dispatch_values.PushValue(*(argument_values.GetValueAtIndex(sel_index))); if (log) { log->Printf("Resolving method call for class - 0x%llx and selector - 0x%llx", dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(), dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong()); } lldb::addr_t impl_addr = LookupInCache (dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(), dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong()); if (impl_addr == LLDB_INVALID_ADDRESS) { Address resolve_address(NULL, this_dispatch->stret_return ? m_impl_stret_fn_addr : m_impl_fn_addr); StreamString errors; { // Scope for mutex locker: Mutex::Locker locker(m_impl_function_mutex); if (!m_impl_function.get()) { m_impl_function.reset(new ClangFunction(process->GetTargetTriple().GetCString(), clang_ast_context, clang_void_ptr_type, resolve_address, dispatch_values)); unsigned num_errors = m_impl_function->CompileFunction(errors); if (num_errors) { if (log) log->Printf ("Error compiling function: \"%s\".", errors.GetData()); return ret_plan_sp; } errors.Clear(); if (!m_impl_function->WriteFunctionWrapper(exec_ctx, errors)) { if (log) log->Printf ("Error Inserting function: \"%s\".", errors.GetData()); return ret_plan_sp; } } } errors.Clear(); // Now write down the argument values for this call. lldb::addr_t args_addr = LLDB_INVALID_ADDRESS; if (!m_impl_function->WriteFunctionArguments (exec_ctx, args_addr, resolve_address, dispatch_values, errors)) return ret_plan_sp; ret_plan_sp.reset (new ThreadPlanStepThroughObjCTrampoline (thread, this, args_addr, argument_values.GetValueAtIndex(0)->GetScalar().ULongLong(), dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(), dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong(), stop_others)); } else { if (log) log->Printf ("Found implementation address in cache: 0x%llx", impl_addr); ret_plan_sp.reset (new ThreadPlanRunToAddress (thread, impl_addr, stop_others)); } } return ret_plan_sp; }
bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress( ValueObject &in_value, lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name, Address &dynamic_address, Value::ValueType &value_type) { // For Itanium, if the type has a vtable pointer in the object, it will be at // offset 0 // in the object. That will point to the "address point" within the vtable // (not the beginning of the // vtable.) We can then look up the symbol containing this "address point" // and that symbol's name // demangled will contain the full class name. // The second pointer above the "address point" is the "offset_to_top". We'll // use that to get the // start of the value object which holds the dynamic type. // class_type_or_name.Clear(); value_type = Value::ValueType::eValueTypeScalar; // Only a pointer or reference type can have a different dynamic and static // type: if (CouldHaveDynamicValue(in_value)) { // First job, pull out the address at 0 offset from the object. AddressType address_type; lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type); if (original_ptr == LLDB_INVALID_ADDRESS) return false; ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); Process *process = exe_ctx.GetProcessPtr(); if (process == nullptr) return false; Error error; const lldb::addr_t vtable_address_point = process->ReadPointerFromMemory(original_ptr, error); if (!error.Success() || vtable_address_point == LLDB_INVALID_ADDRESS) { return false; } class_type_or_name = GetTypeInfoFromVTableAddress(in_value, original_ptr, vtable_address_point); if (class_type_or_name) { TypeSP type_sp = class_type_or_name.GetTypeSP(); // There can only be one type with a given name, // so we've just found duplicate definitions, and this // one will do as well as any other. // We don't consider something to have a dynamic type if // it is the same as the static type. So compare against // the value we were handed. if (type_sp) { if (ClangASTContext::AreTypesSame(in_value.GetCompilerType(), type_sp->GetForwardCompilerType())) { // The dynamic type we found was the same type, // so we don't have a dynamic type here... return false; } // The offset_to_top is two pointers above the vtable pointer. const uint32_t addr_byte_size = process->GetAddressByteSize(); const lldb::addr_t offset_to_top_location = vtable_address_point - 2 * addr_byte_size; // Watch for underflow, offset_to_top_location should be less than // vtable_address_point if (offset_to_top_location >= vtable_address_point) return false; const int64_t offset_to_top = process->ReadSignedIntegerFromMemory( offset_to_top_location, addr_byte_size, INT64_MIN, error); if (offset_to_top == INT64_MIN) return false; // So the dynamic type is a value that starts at offset_to_top // above the original address. lldb::addr_t dynamic_addr = original_ptr + offset_to_top; if (!process->GetTarget().GetSectionLoadList().ResolveLoadAddress( dynamic_addr, dynamic_address)) { dynamic_address.SetRawAddress(dynamic_addr); } return true; } } } return class_type_or_name.IsEmpty() == false; }
bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value, lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name, Address &dynamic_address) { // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0 // in the object. That will point to the "address point" within the vtable (not the beginning of the // vtable.) We can then look up the symbol containing this "address point" and that symbol's name // demangled will contain the full class name. // The second pointer above the "address point" is the "offset_to_top". We'll use that to get the // start of the value object which holds the dynamic type. // class_type_or_name.Clear(); // Only a pointer or reference type can have a different dynamic and static type: if (CouldHaveDynamicValue (in_value)) { // First job, pull out the address at 0 offset from the object. AddressType address_type; lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type); if (original_ptr == LLDB_INVALID_ADDRESS) return false; ExecutionContext exe_ctx (in_value.GetExecutionContextRef()); Target *target = exe_ctx.GetTargetPtr(); Process *process = exe_ctx.GetProcessPtr(); char memory_buffer[16]; DataExtractor data(memory_buffer, sizeof(memory_buffer), process->GetByteOrder(), process->GetAddressByteSize()); size_t address_byte_size = process->GetAddressByteSize(); Error error; size_t bytes_read = process->ReadMemory (original_ptr, memory_buffer, address_byte_size, error); if (!error.Success() || (bytes_read != address_byte_size)) { return false; } lldb::offset_t offset = 0; lldb::addr_t vtable_address_point = data.GetAddress (&offset); if (offset == 0) return false; // Now find the symbol that contains this address: SymbolContext sc; Address address_point_address; if (target && !target->GetSectionLoadList().IsEmpty()) { if (target->GetSectionLoadList().ResolveLoadAddress (vtable_address_point, address_point_address)) { target->GetImages().ResolveSymbolContextForAddress (address_point_address, eSymbolContextSymbol, sc); Symbol *symbol = sc.symbol; if (symbol != NULL) { const char *name = symbol->GetMangled().GetDemangledName().AsCString(); if (strstr(name, vtable_demangled_prefix) == name) { Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); if (log) log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has vtable symbol '%s'\n", original_ptr, in_value.GetTypeName().GetCString(), name); // We are a C++ class, that's good. Get the class name and look it up: const char *class_name = name + strlen(vtable_demangled_prefix); class_type_or_name.SetName (class_name); const bool exact_match = true; TypeList class_types; uint32_t num_matches = 0; // First look in the module that the vtable symbol came from // and look for a single exact match. if (sc.module_sp) { num_matches = sc.module_sp->FindTypes (sc, ConstString(class_name), exact_match, 1, class_types); } // If we didn't find a symbol, then move on to the entire // module list in the target and get as many unique matches // as possible if (num_matches == 0) { num_matches = target->GetImages().FindTypes (sc, ConstString(class_name), exact_match, UINT32_MAX, class_types); } lldb::TypeSP type_sp; if (num_matches == 0) { if (log) log->Printf("0x%16.16" PRIx64 ": is not dynamic\n", original_ptr); return false; } if (num_matches == 1) { type_sp = class_types.GetTypeAtIndex(0); if (log) log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 "}, type-name='%s'\n", original_ptr, in_value.GetTypeName().AsCString(), type_sp->GetID(), type_sp->GetName().GetCString()); class_type_or_name.SetTypeSP(class_types.GetTypeAtIndex(0)); } else if (num_matches > 1) { size_t i; if (log) { for (i = 0; i < num_matches; i++) { type_sp = class_types.GetTypeAtIndex(i); if (type_sp) { if (log) log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types: uid={0x%" PRIx64 "}, type-name='%s'\n", original_ptr, in_value.GetTypeName().AsCString(), type_sp->GetID(), type_sp->GetName().GetCString()); } } } for (i = 0; i < num_matches; i++) { type_sp = class_types.GetTypeAtIndex(i); if (type_sp) { if (type_sp->GetClangFullType().IsCXXClassType()) { if (log) log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, picking this one: uid={0x%" PRIx64 "}, type-name='%s'\n", original_ptr, in_value.GetTypeName().AsCString(), type_sp->GetID(), type_sp->GetName().GetCString()); class_type_or_name.SetTypeSP(type_sp); break; } } } if (i == num_matches) { if (log) log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, didn't find a C++ match\n", original_ptr, in_value.GetTypeName().AsCString()); return false; } } // There can only be one type with a given name, // so we've just found duplicate definitions, and this // one will do as well as any other. // We don't consider something to have a dynamic type if // it is the same as the static type. So compare against // the value we were handed. if (type_sp) { if (ClangASTContext::AreTypesSame (in_value.GetClangType(), type_sp->GetClangFullType())) { // The dynamic type we found was the same type, // so we don't have a dynamic type here... return false; } // The offset_to_top is two pointers above the address. Address offset_to_top_address = address_point_address; int64_t slide = -2 * ((int64_t) target->GetArchitecture().GetAddressByteSize()); offset_to_top_address.Slide (slide); Error error; lldb::addr_t offset_to_top_location = offset_to_top_address.GetLoadAddress(target); size_t bytes_read = process->ReadMemory (offset_to_top_location, memory_buffer, address_byte_size, error); if (!error.Success() || (bytes_read != address_byte_size)) { return false; } offset = 0; int64_t offset_to_top = data.GetMaxS64(&offset, process->GetAddressByteSize()); // So the dynamic type is a value that starts at offset_to_top // above the original address. lldb::addr_t dynamic_addr = original_ptr + offset_to_top; if (!target->GetSectionLoadList().ResolveLoadAddress (dynamic_addr, dynamic_address)) { dynamic_address.SetRawAddress(dynamic_addr); } return true; } } } } } } return class_type_or_name.IsEmpty() == false; }
CPPLanguageRuntime::LibCppStdFunctionCallableInfo CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( lldb::ValueObjectSP &valobj_sp) { LibCppStdFunctionCallableInfo optional_info; if (!valobj_sp) return optional_info; // Member __f_ has type __base*, the contents of which will hold: // 1) a vtable entry which may hold type information needed to discover the // lambda being called // 2) possibly hold a pointer to the callable object // e.g. // // (lldb) frame var -R f_display // (std::__1::function<void (int)>) f_display = { // __buf_ = { // … // } // __f_ = 0x00007ffeefbffa00 // } // (lldb) memory read -fA 0x00007ffeefbffa00 // 0x7ffeefbffa00: ... `vtable for std::__1::__function::__func<void (*) ... // 0x7ffeefbffa08: ... `print_num(int) at std_function_cppreference_exam ... // // We will be handling five cases below, std::function is wrapping: // // 1) a lambda we know at compile time. We will obtain the name of the lambda // from the first template pameter from __func's vtable. We will look up // the lambda's operator()() and obtain the line table entry. // 2) a lambda we know at runtime. A pointer to the lambdas __invoke method // will be stored after the vtable. We will obtain the lambdas name from // this entry and lookup operator()() and obtain the line table entry. // 3) a callable object via operator()(). We will obtain the name of the // object from the first template parameter from __func's vtable. We will // look up the objectc operator()() and obtain the line table entry. // 4) a member function. A pointer to the function will stored after the // we will obtain the name from this pointer. // 5) a free function. A pointer to the function will stored after the vtable // we will obtain the name from this pointer. ValueObjectSP member__f_( valobj_sp->GetChildMemberWithName(ConstString("__f_"), true)); if (member__f_) { ValueObjectSP sub_member__f_( member__f_->GetChildMemberWithName(ConstString("__f_"), true)); if (sub_member__f_) member__f_ = sub_member__f_; } lldb::addr_t member__f_pointer_value = member__f_->GetValueAsUnsigned(0); optional_info.member__f_pointer_value = member__f_pointer_value; ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef()); Process *process = exe_ctx.GetProcessPtr(); if (process == nullptr) return optional_info; uint32_t address_size = process->GetAddressByteSize(); Status status; // First item pointed to by __f_ should be the pointer to the vtable for // a __base object. lldb::addr_t vtable_address = process->ReadPointerFromMemory(member__f_pointer_value, status); if (status.Fail()) return optional_info; lldb::addr_t address_after_vtable = member__f_pointer_value + address_size; // As commened above we may not have a function pointer but if we do we will // need it. lldb::addr_t possible_function_address = process->ReadPointerFromMemory(address_after_vtable, status); if (status.Fail()) return optional_info; Target &target = process->GetTarget(); if (target.GetSectionLoadList().IsEmpty()) return optional_info; Address vtable_addr_resolved; SymbolContext sc; Symbol *symbol; if (!target.GetSectionLoadList().ResolveLoadAddress(vtable_address, vtable_addr_resolved)) return optional_info; target.GetImages().ResolveSymbolContextForAddress( vtable_addr_resolved, eSymbolContextEverything, sc); symbol = sc.symbol; if (symbol == nullptr) return optional_info; llvm::StringRef vtable_name(symbol->GetName().GetCString()); bool found_expected_start_string = vtable_name.startswith("vtable for std::__1::__function::__func<"); if (!found_expected_start_string) return optional_info; // Given case 1 or 3 we have a vtable name, we are want to extract the first // template parameter // // ... __func<main::$_0, std::__1::allocator<main::$_0> ... // ^^^^^^^^^ // // We do this by find the first < and , and extracting in between. // // This covers the case of the lambda known at compile time. size_t first_open_angle_bracket = vtable_name.find('<') + 1; size_t first_comma = vtable_name.find(','); llvm::StringRef first_template_parameter = vtable_name.slice(first_open_angle_bracket, first_comma); Address function_address_resolved; // Setup for cases 2, 4 and 5 we have a pointer to a function after the // vtable. We will use a process of elimination to drop through each case // and obtain the data we need. if (target.GetSectionLoadList().ResolveLoadAddress( possible_function_address, function_address_resolved)) { target.GetImages().ResolveSymbolContextForAddress( function_address_resolved, eSymbolContextEverything, sc); symbol = sc.symbol; } auto get_name = [&first_template_parameter, &symbol]() { // Given case 1: // // main::$_0 // // we want to append ::operator()() if (first_template_parameter.contains("$_")) return llvm::Regex::escape(first_template_parameter.str()) + R"(::operator\(\)\(.*\))"; if (symbol != NULL && symbol->GetName().GetStringRef().contains("__invoke")) { llvm::StringRef symbol_name = symbol->GetName().GetStringRef(); size_t pos2 = symbol_name.find_last_of(':'); // Given case 2: // // main::$_1::__invoke(...) // // We want to slice off __invoke(...) and append operator()() std::string lambda_operator = llvm::Regex::escape(symbol_name.slice(0, pos2 + 1).str()) + R"(operator\(\)\(.*\))"; return lambda_operator; } // Case 3 return first_template_parameter.str() + R"(::operator\(\)\(.*\))"; ; }; std::string func_to_match = get_name(); SymbolContextList scl; target.GetImages().FindFunctions(RegularExpression{func_to_match}, true, true, true, scl); // Case 1,2 or 3 if (scl.GetSize() >= 1) { SymbolContext sc2 = scl[0]; AddressRange range; sc2.GetAddressRange(eSymbolContextEverything, 0, false, range); Address address = range.GetBaseAddress(); Address addr; if (target.ResolveLoadAddress(address.GetCallableLoadAddress(&target), addr)) { LineEntry line_entry; addr.CalculateSymbolContextLineEntry(line_entry); if (first_template_parameter.contains("$_") || (symbol != nullptr && symbol->GetName().GetStringRef().contains("__invoke"))) { // Case 1 and 2 optional_info.callable_case = LibCppStdFunctionCallableCase::Lambda; } else { // Case 3 optional_info.callable_case = LibCppStdFunctionCallableCase::CallableObject; } optional_info.callable_symbol = *symbol; optional_info.callable_line_entry = line_entry; optional_info.callable_address = addr; return optional_info; }
bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value, lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name, Address &dynamic_address) { // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0 // in the object. That will point to the "address point" within the vtable (not the beginning of the // vtable.) We can then look up the symbol containing this "address point" and that symbol's name // demangled will contain the full class name. // The second pointer above the "address point" is the "offset_to_top". We'll use that to get the // start of the value object which holds the dynamic type. // // Only a pointer or reference type can have a different dynamic and static type: if (CouldHaveDynamicValue (in_value)) { // FIXME: Can we get the Clang Type and ask it if the thing is really virtual? That would avoid false positives, // at the cost of not looking for the dynamic type of objects if DWARF->Clang gets it wrong. // First job, pull out the address at 0 offset from the object. AddressType address_type; lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type); if (original_ptr == LLDB_INVALID_ADDRESS) return false; Target *target = in_value.GetUpdatePoint().GetTargetSP().get(); Process *process = in_value.GetUpdatePoint().GetProcessSP().get(); char memory_buffer[16]; DataExtractor data(memory_buffer, sizeof(memory_buffer), process->GetByteOrder(), process->GetAddressByteSize()); size_t address_byte_size = process->GetAddressByteSize(); Error error; size_t bytes_read = process->ReadMemory (original_ptr, memory_buffer, address_byte_size, error); if (!error.Success() || (bytes_read != address_byte_size)) { return false; } uint32_t offset_ptr = 0; lldb::addr_t vtable_address_point = data.GetAddress (&offset_ptr); if (offset_ptr == 0) return false; // Now find the symbol that contains this address: SymbolContext sc; Address address_point_address; if (target && !target->GetSectionLoadList().IsEmpty()) { if (target->GetSectionLoadList().ResolveLoadAddress (vtable_address_point, address_point_address)) { target->GetImages().ResolveSymbolContextForAddress (address_point_address, eSymbolContextSymbol, sc); Symbol *symbol = sc.symbol; if (symbol != NULL) { const char *name = symbol->GetMangled().GetDemangledName().AsCString(); if (strstr(name, vtable_demangled_prefix) == name) { // We are a C++ class, that's good. Get the class name and look it up: const char *class_name = name + strlen(vtable_demangled_prefix); class_type_or_name.SetName (class_name); TypeList class_types; uint32_t num_matches = target->GetImages().FindTypes (sc, ConstString(class_name), true, UINT32_MAX, class_types); if (num_matches == 1) { class_type_or_name.SetTypeSP(class_types.GetTypeAtIndex(0)); } else if (num_matches > 1) { for (size_t i = 0; i < num_matches; i++) { lldb::TypeSP this_type(class_types.GetTypeAtIndex(i)); if (this_type) { if (ClangASTContext::IsCXXClassType(this_type->GetClangFullType())) { // There can only be one type with a given name, // so we've just found duplicate definitions, and this // one will do as well as any other. // We don't consider something to have a dynamic type if // it is the same as the static type. So compare against // the value we were handed: clang::ASTContext *in_ast_ctx = in_value.GetClangAST (); clang::ASTContext *this_ast_ctx = this_type->GetClangAST (); if (in_ast_ctx != this_ast_ctx || !ClangASTContext::AreTypesSame (in_ast_ctx, in_value.GetClangType(), this_type->GetClangFullType())) { class_type_or_name.SetTypeSP (this_type); return true; } return false; } } } } else return false; // The offset_to_top is two pointers above the address. Address offset_to_top_address = address_point_address; int64_t slide = -2 * ((int64_t) target->GetArchitecture().GetAddressByteSize()); offset_to_top_address.Slide (slide); Error error; lldb::addr_t offset_to_top_location = offset_to_top_address.GetLoadAddress(target); size_t bytes_read = process->ReadMemory (offset_to_top_location, memory_buffer, address_byte_size, error); if (!error.Success() || (bytes_read != address_byte_size)) { return false; } offset_ptr = 0; int64_t offset_to_top = data.GetMaxS64(&offset_ptr, process->GetAddressByteSize()); // So the dynamic type is a value that starts at offset_to_top // above the original address. lldb::addr_t dynamic_addr = original_ptr + offset_to_top; if (!target->GetSectionLoadList().ResolveLoadAddress (dynamic_addr, dynamic_address)) { dynamic_address.SetOffset(dynamic_addr); dynamic_address.SetSection(NULL); } return true; } } } } } return false; }
bool FunctionCaller::WriteFunctionArguments( ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, ValueList &arg_values, DiagnosticManager &diagnostic_manager) { // All the information to reconstruct the struct is provided by the // StructExtractor. if (!m_struct_valid) { diagnostic_manager.PutString(eDiagnosticSeverityError, "Argument information was not correctly " "parsed, so the function cannot be called."); return false; } Status error; lldb::ExpressionResults return_value = lldb::eExpressionSetupError; Process *process = exe_ctx.GetProcessPtr(); if (process == NULL) return return_value; lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock()); if (process != jit_process_sp.get()) return false; if (args_addr_ref == LLDB_INVALID_ADDRESS) { args_addr_ref = process->AllocateMemory( m_struct_size, lldb::ePermissionsReadable | lldb::ePermissionsWritable, error); if (args_addr_ref == LLDB_INVALID_ADDRESS) return false; m_wrapper_args_addrs.push_back(args_addr_ref); } else { // Make sure this is an address that we've already handed out. if (find(m_wrapper_args_addrs.begin(), m_wrapper_args_addrs.end(), args_addr_ref) == m_wrapper_args_addrs.end()) { return false; } } // TODO: verify fun_addr needs to be a callable address Scalar fun_addr( m_function_addr.GetCallableLoadAddress(exe_ctx.GetTargetPtr())); uint64_t first_offset = m_member_offsets[0]; process->WriteScalarToMemory(args_addr_ref + first_offset, fun_addr, process->GetAddressByteSize(), error); // FIXME: We will need to extend this for Variadic functions. Status value_error; size_t num_args = arg_values.GetSize(); if (num_args != m_arg_values.GetSize()) { diagnostic_manager.Printf( eDiagnosticSeverityError, "Wrong number of arguments - was: %" PRIu64 " should be: %" PRIu64 "", (uint64_t)num_args, (uint64_t)m_arg_values.GetSize()); return false; } for (size_t i = 0; i < num_args; i++) { // FIXME: We should sanity check sizes. uint64_t offset = m_member_offsets[i + 1]; // Clang sizes are in bytes. Value *arg_value = arg_values.GetValueAtIndex(i); // FIXME: For now just do scalars: // Special case: if it's a pointer, don't do anything (the ABI supports // passing cstrings) if (arg_value->GetValueType() == Value::eValueTypeHostAddress && arg_value->GetContextType() == Value::eContextTypeInvalid && arg_value->GetCompilerType().IsPointerType()) continue; const Scalar &arg_scalar = arg_value->ResolveValue(&exe_ctx); if (!process->WriteScalarToMemory(args_addr_ref + offset, arg_scalar, arg_scalar.GetByteSize(), error)) return false; } return true; }