bool CommandObjectArgs::DoExecute (Args& args, CommandReturnObject &result) { ConstString target_triple; Process *process = m_exe_ctx.GetProcessPtr(); if (!process) { result.AppendError ("Args found no process."); result.SetStatus (eReturnStatusFailed); return false; } const ABI *abi = process->GetABI().get(); if (!abi) { result.AppendError ("The current process has no ABI."); result.SetStatus (eReturnStatusFailed); return false; } const size_t num_args = args.GetArgumentCount (); size_t arg_index; if (!num_args) { result.AppendError ("args requires at least one argument"); result.SetStatus (eReturnStatusFailed); return false; } Thread *thread = m_exe_ctx.GetThreadPtr(); if (!thread) { result.AppendError ("args found no thread."); result.SetStatus (eReturnStatusFailed); return false; } lldb::StackFrameSP thread_cur_frame = thread->GetSelectedFrame (); if (!thread_cur_frame) { result.AppendError ("The current thread has no current frame."); result.SetStatus (eReturnStatusFailed); return false; } ModuleSP thread_module_sp (thread_cur_frame->GetFrameCodeAddress ().GetModule()); if (!thread_module_sp) { result.AppendError ("The PC has no associated module."); result.SetStatus (eReturnStatusFailed); return false; } ClangASTContext &ast_context = thread_module_sp->GetClangASTContext(); ValueList value_list; for (arg_index = 0; arg_index < num_args; ++arg_index) { const char *arg_type_cstr = args.GetArgumentAtIndex(arg_index); Value value; value.SetValueType(Value::eValueTypeScalar); void *type; char *int_pos; if ((int_pos = strstr (const_cast<char*>(arg_type_cstr), "int"))) { Encoding encoding = eEncodingSint; int width = 0; if (int_pos > arg_type_cstr + 1) { result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr); result.SetStatus (eReturnStatusFailed); return false; } if (int_pos == arg_type_cstr + 1 && arg_type_cstr[0] != 'u') { result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr); result.SetStatus (eReturnStatusFailed); return false; } if (arg_type_cstr[0] == 'u') { encoding = eEncodingUint; } char *width_pos = int_pos + 3; if (!strcmp (width_pos, "8_t")) width = 8; else if (!strcmp (width_pos, "16_t")) width = 16; else if (!strcmp (width_pos, "32_t")) width = 32; else if (!strcmp (width_pos, "64_t")) width = 64; else { result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr); result.SetStatus (eReturnStatusFailed); return false; } type = ast_context.GetBuiltinTypeForEncodingAndBitSize(encoding, width); if (!type) { result.AppendErrorWithFormat ("Couldn't get Clang type for format %s (%s integer, width %d).\n", arg_type_cstr, (encoding == eEncodingSint ? "signed" : "unsigned"), width); result.SetStatus (eReturnStatusFailed); return false; } } else if (strchr (arg_type_cstr, '*')) { if (!strcmp (arg_type_cstr, "void*")) type = ast_context.CreatePointerType (ast_context.GetBuiltInType_void ()); else if (!strcmp (arg_type_cstr, "char*")) type = ast_context.GetCStringType (false); else { result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr); result.SetStatus (eReturnStatusFailed); return false; } } else { result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr); result.SetStatus (eReturnStatusFailed); return false; } value.SetContext (Value::eContextTypeClangType, type); value_list.PushValue(value); } if (!abi->GetArgumentValues (*thread, value_list)) { result.AppendError ("Couldn't get argument values"); result.SetStatus (eReturnStatusFailed); return false; } result.GetOutputStream ().Printf("Arguments : \n"); for (arg_index = 0; arg_index < num_args; ++arg_index) { result.GetOutputStream ().Printf ("%zu (%s): ", arg_index, args.GetArgumentAtIndex (arg_index)); value_list.GetValueAtIndex (arg_index)->Dump (&result.GetOutputStream ()); result.GetOutputStream ().Printf("\n"); } return result.Succeeded(); }
bool CommandObjectArgs::DoExecute(Args &args, CommandReturnObject &result) { ConstString target_triple; Process *process = m_exe_ctx.GetProcessPtr(); if (!process) { result.AppendError("Args found no process."); result.SetStatus(eReturnStatusFailed); return false; } const ABI *abi = process->GetABI().get(); if (!abi) { result.AppendError("The current process has no ABI."); result.SetStatus(eReturnStatusFailed); return false; } if (args.empty()) { result.AppendError("args requires at least one argument"); result.SetStatus(eReturnStatusFailed); return false; } Thread *thread = m_exe_ctx.GetThreadPtr(); if (!thread) { result.AppendError("args found no thread."); result.SetStatus(eReturnStatusFailed); return false; } lldb::StackFrameSP thread_cur_frame = thread->GetSelectedFrame(); if (!thread_cur_frame) { result.AppendError("The current thread has no current frame."); result.SetStatus(eReturnStatusFailed); return false; } ModuleSP thread_module_sp( thread_cur_frame->GetFrameCodeAddress().GetModule()); if (!thread_module_sp) { result.AppendError("The PC has no associated module."); result.SetStatus(eReturnStatusFailed); return false; } TypeSystem *type_system = thread_module_sp->GetTypeSystemForLanguage(eLanguageTypeC); if (type_system == nullptr) { result.AppendError("Unable to create C type system."); result.SetStatus(eReturnStatusFailed); return false; } ValueList value_list; for (auto &arg_entry : args.entries()) { llvm::StringRef arg_type = arg_entry.ref; Value value; value.SetValueType(Value::eValueTypeScalar); CompilerType compiler_type; std::size_t int_pos = arg_type.find("int"); if (int_pos != llvm::StringRef::npos) { Encoding encoding = eEncodingSint; int width = 0; if (int_pos > 1) { result.AppendErrorWithFormat("Invalid format: %s.\n", arg_entry.c_str()); result.SetStatus(eReturnStatusFailed); return false; } if (int_pos == 1 && arg_type[0] != 'u') { result.AppendErrorWithFormat("Invalid format: %s.\n", arg_entry.c_str()); result.SetStatus(eReturnStatusFailed); return false; } if (arg_type[0] == 'u') { encoding = eEncodingUint; } llvm::StringRef width_spec = arg_type.drop_front(int_pos + 3); auto exp_result = llvm::StringSwitch<llvm::Optional<int>>(width_spec) .Case("8_t", 8) .Case("16_t", 16) .Case("32_t", 32) .Case("64_t", 64) .Default(llvm::None); if (!exp_result.hasValue()) { result.AppendErrorWithFormat("Invalid format: %s.\n", arg_entry.c_str()); result.SetStatus(eReturnStatusFailed); return false; } width = *exp_result; compiler_type = type_system->GetBuiltinTypeForEncodingAndBitSize(encoding, width); if (!compiler_type.IsValid()) { result.AppendErrorWithFormat( "Couldn't get Clang type for format %s (%s integer, width %d).\n", arg_entry.c_str(), (encoding == eEncodingSint ? "signed" : "unsigned"), width); result.SetStatus(eReturnStatusFailed); return false; } } else if (arg_type == "void*") { compiler_type = type_system->GetBasicTypeFromAST(eBasicTypeVoid).GetPointerType(); } else if (arg_type == "char*") { compiler_type = type_system->GetBasicTypeFromAST(eBasicTypeChar).GetPointerType(); } else { result.AppendErrorWithFormat("Invalid format: %s.\n", arg_entry.c_str()); result.SetStatus(eReturnStatusFailed); return false; } value.SetCompilerType(compiler_type); value_list.PushValue(value); } if (!abi->GetArgumentValues(*thread, value_list)) { result.AppendError("Couldn't get argument values"); result.SetStatus(eReturnStatusFailed); return false; } result.GetOutputStream().Printf("Arguments : \n"); for (auto entry : llvm::enumerate(args.entries())) { result.GetOutputStream().Printf("%" PRIu64 " (%s): ", (uint64_t)entry.Index, entry.Value.c_str()); value_list.GetValueAtIndex(entry.Index)->Dump(&result.GetOutputStream()); result.GetOutputStream().Printf("\n"); } return result.Succeeded(); }
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; }
// Static callback function that gets called when our DYLD notification // breakpoint gets hit. We update all of our image infos and then let our super // class DynamicLoader class decide if we should stop or not (based on global // preference). bool DynamicLoaderMacOSXDYLD::NotifyBreakpointHit( void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id) { // Let the event know that the images have changed // DYLD passes three arguments to the notification breakpoint. // Arg1: enum dyld_image_mode mode - 0 = adding, 1 = removing Arg2: uint32_t // infoCount - Number of shared libraries added Arg3: dyld_image_info // info[] - Array of structs of the form: // const struct mach_header // *imageLoadAddress // const char *imageFilePath // uintptr_t imageFileModDate (a time_t) DynamicLoaderMacOSXDYLD *dyld_instance = (DynamicLoaderMacOSXDYLD *)baton; // First step is to see if we've already initialized the all image infos. If // we haven't then this function will do so and return true. In the course // of initializing the all_image_infos it will read the complete current // state, so we don't need to figure out what has changed from the data // passed in to us. ExecutionContext exe_ctx(context->exe_ctx_ref); Process *process = exe_ctx.GetProcessPtr(); // This is a sanity check just in case this dyld_instance is an old dyld // plugin's breakpoint still lying around. if (process != dyld_instance->m_process) return false; if (dyld_instance->InitializeFromAllImageInfos()) return dyld_instance->GetStopWhenImagesChange(); const lldb::ABISP &abi = process->GetABI(); if (abi) { // Build up the value array to store the three arguments given above, then // get the values from the ABI: ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext(); ValueList argument_values; Value input_value; CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); CompilerType clang_uint32_type = clang_ast_context->GetBuiltinTypeForEncodingAndBitSize( lldb::eEncodingUint, 32); input_value.SetValueType(Value::eValueTypeScalar); input_value.SetCompilerType(clang_uint32_type); // input_value.SetContext (Value::eContextTypeClangType, // clang_uint32_type); argument_values.PushValue(input_value); argument_values.PushValue(input_value); input_value.SetCompilerType(clang_void_ptr_type); // input_value.SetContext (Value::eContextTypeClangType, // clang_void_ptr_type); argument_values.PushValue(input_value); if (abi->GetArgumentValues(exe_ctx.GetThreadRef(), argument_values)) { uint32_t dyld_mode = argument_values.GetValueAtIndex(0)->GetScalar().UInt(-1); if (dyld_mode != static_cast<uint32_t>(-1)) { // Okay the mode was right, now get the number of elements, and the // array of new elements... uint32_t image_infos_count = argument_values.GetValueAtIndex(1)->GetScalar().UInt(-1); if (image_infos_count != static_cast<uint32_t>(-1)) { // Got the number added, now go through the array of added elements, // putting out the mach header address, and adding the image. Note, // I'm not putting in logging here, since the AddModules & // RemoveModules functions do all the logging internally. lldb::addr_t image_infos_addr = argument_values.GetValueAtIndex(2)->GetScalar().ULongLong(); if (dyld_mode == 0) { // This is add: dyld_instance->AddModulesUsingImageInfosAddress(image_infos_addr, image_infos_count); } else { // This is remove: dyld_instance->RemoveModulesUsingImageInfosAddress( image_infos_addr, image_infos_count); } } } } } else { process->GetTarget().GetDebugger().GetAsyncErrorStream()->Printf( "No ABI plugin located for triple %s -- shared libraries will not be " "registered!\n", process->GetTarget().GetArchitecture().GetTriple().getTriple().c_str()); } // Return true to stop the target, false to just let the target run return dyld_instance->GetStopWhenImagesChange(); }