SBError SBThread::ResumeNewPlan(ExecutionContext &exe_ctx, ThreadPlan *new_plan) { SBError sb_error; Process *process = exe_ctx.GetProcessPtr(); if (!process) { sb_error.SetErrorString("No process in SBThread::ResumeNewPlan"); return sb_error; } Thread *thread = exe_ctx.GetThreadPtr(); if (!thread) { sb_error.SetErrorString("No thread in SBThread::ResumeNewPlan"); return sb_error; } // User level plans should be Master Plans so they can be interrupted, other // plans executed, and // then a "continue" will resume the plan. if (new_plan != NULL) { new_plan->SetIsMasterPlan(true); new_plan->SetOkayToDiscard(false); } // Why do we need to set the current thread by ID here??? process->GetThreadList().SetSelectedThreadByID(thread->GetID()); if (process->GetTarget().GetDebugger().GetAsyncExecution()) sb_error.ref() = process->Resume(); else sb_error.ref() = process->ResumeSynchronous(NULL); return sb_error; }
clang::ASTContext * ValueObjectRegister::GetClangAST () { Process *process = m_reg_ctx_sp->CalculateProcess (); if (process) { Module *exe_module = process->GetTarget().GetExecutableModulePointer(); if (exe_module) return exe_module->GetClangASTContext().getASTContext(); } return NULL; }
bool ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) { Process *process = exe_ctx.GetProcessPtr(); if (!process) return false; lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock()); if (process != jit_process_sp.get()) return false; if (!m_compiled) return false; if (m_JITted) return true; bool can_interpret = false; // should stay that way Error jit_error (m_parser->PrepareForExecution (m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx, can_interpret, eExecutionPolicyAlways)); if (!jit_error.Success()) return false; if (m_parser->GetGenerateDebugInfo()) { lldb::ModuleSP jit_module_sp ( m_execution_unit_sp->GetJITModule()); if (jit_module_sp) { ConstString const_func_name(FunctionName()); FileSpec jit_file; jit_file.GetFilename() = const_func_name; jit_module_sp->SetFileSpecAndObjectName (jit_file, ConstString()); m_jit_module_wp = jit_module_sp; process->GetTarget().GetImages().Append(jit_module_sp); } } if (process && m_jit_start_addr) m_jit_process_wp = process->shared_from_this(); m_JITted = true; return true; }
lldb::clang_type_t ValueObjectRegister::GetClangType () { if (m_clang_type == NULL) { Process *process = m_reg_ctx_sp->CalculateProcess (); if (process) { Module *exe_module = process->GetTarget().GetExecutableModulePointer(); if (exe_module) { m_clang_type = exe_module->GetClangASTContext().GetBuiltinTypeForEncodingAndBitSize (m_reg_info.encoding, m_reg_info.byte_size * 8); } } } return m_clang_type; }
lldb::ModuleSP AppleObjCRuntime::GetObjCModule () { ModuleSP module_sp (m_objc_module_wp.lock()); if (module_sp) return module_sp; Process *process = GetProcess(); if (process) { const ModuleList& modules = process->GetTarget().GetImages(); for (uint32_t idx = 0; idx < modules.GetSize(); idx++) { module_sp = modules.GetModuleAtIndex(idx); if (AppleObjCRuntime::AppleIsModuleObjCLibrary(module_sp)) { m_objc_module_wp = module_sp; return module_sp; } } } return ModuleSP(); }
Error Value::GetValueAsData (ExecutionContext *exe_ctx, DataExtractor &data, uint32_t data_offset, Module *module) { data.Clear(); Error error; lldb::addr_t address = LLDB_INVALID_ADDRESS; AddressType address_type = eAddressTypeFile; Address file_so_addr; const CompilerType &ast_type = GetCompilerType(); switch (m_value_type) { case eValueTypeVector: if (ast_type.IsValid()) data.SetAddressByteSize (ast_type.GetPointerByteSize()); else data.SetAddressByteSize(sizeof(void *)); data.SetData(m_vector.bytes, m_vector.length, m_vector.byte_order); break; case eValueTypeScalar: { data.SetByteOrder (endian::InlHostByteOrder()); if (ast_type.IsValid()) data.SetAddressByteSize (ast_type.GetPointerByteSize()); else data.SetAddressByteSize(sizeof(void *)); uint32_t limit_byte_size = UINT32_MAX; if (ast_type.IsValid() && ast_type.IsScalarType()) { uint64_t type_encoding_count = 0; lldb::Encoding type_encoding = ast_type.GetEncoding(type_encoding_count); if (type_encoding == eEncodingUint || type_encoding == eEncodingSint) limit_byte_size = ast_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr); } if (m_value.GetData (data, limit_byte_size)) return error; // Success; error.SetErrorStringWithFormat("extracting data from value failed"); break; } case eValueTypeLoadAddress: if (exe_ctx == NULL) { error.SetErrorString ("can't read load address (no execution context)"); } else { Process *process = exe_ctx->GetProcessPtr(); if (process == NULL || !process->IsAlive()) { Target *target = exe_ctx->GetTargetPtr(); if (target) { // Allow expressions to run and evaluate things when the target // has memory sections loaded. This allows you to use "target modules load" // to load your executable and any shared libraries, then execute // commands where you can look at types in data sections. const SectionLoadList &target_sections = target->GetSectionLoadList(); if (!target_sections.IsEmpty()) { address = m_value.ULongLong(LLDB_INVALID_ADDRESS); if (target_sections.ResolveLoadAddress(address, file_so_addr)) { address_type = eAddressTypeLoad; data.SetByteOrder(target->GetArchitecture().GetByteOrder()); data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); } else address = LLDB_INVALID_ADDRESS; } // else // { // ModuleSP exe_module_sp (target->GetExecutableModule()); // if (exe_module_sp) // { // address = m_value.ULongLong(LLDB_INVALID_ADDRESS); // if (address != LLDB_INVALID_ADDRESS) // { // if (exe_module_sp->ResolveFileAddress(address, file_so_addr)) // { // data.SetByteOrder(target->GetArchitecture().GetByteOrder()); // data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); // address_type = eAddressTypeFile; // } // else // { // address = LLDB_INVALID_ADDRESS; // } // } // } // } } else { error.SetErrorString ("can't read load address (invalid process)"); } } else { address = m_value.ULongLong(LLDB_INVALID_ADDRESS); address_type = eAddressTypeLoad; data.SetByteOrder(process->GetTarget().GetArchitecture().GetByteOrder()); data.SetAddressByteSize(process->GetTarget().GetArchitecture().GetAddressByteSize()); } } break; case eValueTypeFileAddress: if (exe_ctx == NULL) { error.SetErrorString ("can't read file address (no execution context)"); } else if (exe_ctx->GetTargetPtr() == NULL) { error.SetErrorString ("can't read file address (invalid target)"); } else { address = m_value.ULongLong(LLDB_INVALID_ADDRESS); if (address == LLDB_INVALID_ADDRESS) { error.SetErrorString ("invalid file address"); } else { if (module == NULL) { // The only thing we can currently lock down to a module so that // we can resolve a file address, is a variable. Variable *variable = GetVariable(); if (variable) { SymbolContext var_sc; variable->CalculateSymbolContext(&var_sc); module = var_sc.module_sp.get(); } } if (module) { bool resolved = false; ObjectFile *objfile = module->GetObjectFile(); if (objfile) { Address so_addr(address, objfile->GetSectionList()); addr_t load_address = so_addr.GetLoadAddress (exe_ctx->GetTargetPtr()); bool process_launched_and_stopped = exe_ctx->GetProcessPtr() ? StateIsStoppedState(exe_ctx->GetProcessPtr()->GetState(), true /* must_exist */) : false; // Don't use the load address if the process has exited. if (load_address != LLDB_INVALID_ADDRESS && process_launched_and_stopped) { resolved = true; address = load_address; address_type = eAddressTypeLoad; data.SetByteOrder(exe_ctx->GetTargetRef().GetArchitecture().GetByteOrder()); data.SetAddressByteSize(exe_ctx->GetTargetRef().GetArchitecture().GetAddressByteSize()); } else { if (so_addr.IsSectionOffset()) { resolved = true; file_so_addr = so_addr; data.SetByteOrder(objfile->GetByteOrder()); data.SetAddressByteSize(objfile->GetAddressByteSize()); } } } if (!resolved) { Variable *variable = GetVariable(); if (module) { if (variable) error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64 " for variable '%s' in %s", address, variable->GetName().AsCString(""), module->GetFileSpec().GetPath().c_str()); else error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64 " in %s", address, module->GetFileSpec().GetPath().c_str()); } else { if (variable) error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64 " for variable '%s'", address, variable->GetName().AsCString("")); else error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64, address); } } } else { // Can't convert a file address to anything valid without more // context (which Module it came from) error.SetErrorString ("can't read memory from file address without more context"); } } } break; case eValueTypeHostAddress: address = m_value.ULongLong(LLDB_INVALID_ADDRESS); address_type = eAddressTypeHost; if (exe_ctx) { Target *target = exe_ctx->GetTargetPtr(); if (target) { data.SetByteOrder(target->GetArchitecture().GetByteOrder()); data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); break; } } // fallback to host settings data.SetByteOrder(endian::InlHostByteOrder()); data.SetAddressByteSize(sizeof(void *)); break; } // Bail if we encountered any errors if (error.Fail()) return error; if (address == LLDB_INVALID_ADDRESS) { error.SetErrorStringWithFormat ("invalid %s address", address_type == eAddressTypeHost ? "host" : "load"); return error; } // If we got here, we need to read the value from memory size_t byte_size = GetValueByteSize (&error, exe_ctx); // Bail if we encountered any errors getting the byte size if (error.Fail()) return error; // Make sure we have enough room within "data", and if we don't make // something large enough that does if (!data.ValidOffsetForDataOfSize (data_offset, byte_size)) { DataBufferSP data_sp(new DataBufferHeap (data_offset + byte_size, '\0')); data.SetData(data_sp); } uint8_t* dst = const_cast<uint8_t*>(data.PeekData (data_offset, byte_size)); if (dst != NULL) { if (address_type == eAddressTypeHost) { // The address is an address in this process, so just copy it. if (address == 0) { error.SetErrorStringWithFormat("trying to read from host address of 0."); return error; } memcpy (dst, (uint8_t*)NULL + address, byte_size); } else if ((address_type == eAddressTypeLoad) || (address_type == eAddressTypeFile)) { if (file_so_addr.IsValid()) { // We have a file address that we were able to translate into a // section offset address so we might be able to read this from // the object files if we don't have a live process. Lets always // try and read from the process if we have one though since we // want to read the actual value by setting "prefer_file_cache" // to false. const bool prefer_file_cache = false; if (exe_ctx->GetTargetRef().ReadMemory(file_so_addr, prefer_file_cache, dst, byte_size, error) != byte_size) { error.SetErrorStringWithFormat("read memory from 0x%" PRIx64 " failed", (uint64_t)address); } } else { // The execution context might have a NULL process, but it // might have a valid process in the exe_ctx->target, so use // the ExecutionContext::GetProcess accessor to ensure we // get the process if there is one. Process *process = exe_ctx->GetProcessPtr(); if (process) { const size_t bytes_read = process->ReadMemory(address, dst, byte_size, error); if (bytes_read != byte_size) error.SetErrorStringWithFormat("read memory from 0x%" PRIx64 " failed (%u of %u bytes read)", (uint64_t)address, (uint32_t)bytes_read, (uint32_t)byte_size); } else { error.SetErrorStringWithFormat("read memory from 0x%" PRIx64 " failed (invalid process)", (uint64_t)address); } } } else { error.SetErrorStringWithFormat ("unsupported AddressType value (%i)", address_type); } } else { error.SetErrorStringWithFormat ("out of memory"); } return error; }
lldb::ExpressionResults ClangUserExpression::Evaluate (ExecutionContext &exe_ctx, const EvaluateExpressionOptions& options, const char *expr_cstr, const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp, Error &error) { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy(); const lldb::LanguageType language = options.GetLanguage(); const ResultType desired_type = options.DoesCoerceToId() ? ClangUserExpression::eResultTypeId : ClangUserExpression::eResultTypeAny; lldb::ExpressionResults execution_results = lldb::eExpressionSetupError; Process *process = exe_ctx.GetProcessPtr(); if (process == NULL || process->GetState() != lldb::eStateStopped) { if (execution_policy == eExecutionPolicyAlways) { if (log) log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant =="); error.SetErrorString ("expression needed to run but couldn't"); return execution_results; } } if (process == NULL || !process->CanJIT()) execution_policy = eExecutionPolicyNever; ClangUserExpressionSP user_expression_sp (new ClangUserExpression (expr_cstr, expr_prefix, language, desired_type)); StreamString error_stream; if (log) log->Printf("== [ClangUserExpression::Evaluate] Parsing expression %s ==", expr_cstr); const bool keep_expression_in_memory = true; const bool generate_debug_info = options.GetGenerateDebugInfo(); if (options.InvokeCancelCallback (lldb::eExpressionEvaluationParse)) { error.SetErrorString ("expression interrupted by callback before parse"); result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); return lldb::eExpressionInterrupted; } if (!user_expression_sp->Parse (error_stream, exe_ctx, execution_policy, keep_expression_in_memory, generate_debug_info)) { if (error_stream.GetString().empty()) error.SetExpressionError (lldb::eExpressionParseError, "expression failed to parse, unknown error"); else error.SetExpressionError (lldb::eExpressionParseError, error_stream.GetString().c_str()); } else { lldb::ClangExpressionVariableSP expr_result; if (execution_policy == eExecutionPolicyNever && !user_expression_sp->CanInterpret()) { if (log) log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant =="); if (error_stream.GetString().empty()) error.SetExpressionError (lldb::eExpressionSetupError, "expression needed to run but couldn't"); } else { if (options.InvokeCancelCallback (lldb::eExpressionEvaluationExecution)) { error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback before execution"); result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); return lldb::eExpressionInterrupted; } error_stream.GetString().clear(); if (log) log->Printf("== [ClangUserExpression::Evaluate] Executing expression =="); execution_results = user_expression_sp->Execute (error_stream, exe_ctx, options, user_expression_sp, expr_result); if (options.GetResultIsInternal()) { process->GetTarget().GetPersistentVariables().RemovePersistentVariable (expr_result); } if (execution_results != lldb::eExpressionCompleted) { if (log) log->Printf("== [ClangUserExpression::Evaluate] Execution completed abnormally =="); if (error_stream.GetString().empty()) error.SetExpressionError (execution_results, "expression failed to execute, unknown error"); else error.SetExpressionError (execution_results, error_stream.GetString().c_str()); } else { if (expr_result) { result_valobj_sp = expr_result->GetValueObject(); if (log) log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with result %s ==", result_valobj_sp->GetValueAsCString()); } else { if (log) log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with no result =="); error.SetError(ClangUserExpression::kNoResult, lldb::eErrorTypeGeneric); } } } } if (options.InvokeCancelCallback(lldb::eExpressionEvaluationComplete)) { error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback after complete"); return lldb::eExpressionInterrupted; } if (result_valobj_sp.get() == NULL) { result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); } return execution_results; }
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; }
lldb::addr_t AppleObjCRuntimeV1::GetISAHashTablePointer () { if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) { ModuleSP objc_module_sp(GetObjCModule()); if (!objc_module_sp) return LLDB_INVALID_ADDRESS; static ConstString g_objc_debug_class_hash("_objc_debug_class_hash"); const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(g_objc_debug_class_hash, lldb::eSymbolTypeData); if (symbol && symbol->ValueIsAddress()) { Process *process = GetProcess(); if (process) { lldb::addr_t objc_debug_class_hash_addr = symbol->GetAddressRef().GetLoadAddress(&process->GetTarget()); if (objc_debug_class_hash_addr != LLDB_INVALID_ADDRESS) { Error error; lldb::addr_t objc_debug_class_hash_ptr = process->ReadPointerFromMemory(objc_debug_class_hash_addr, error); if (objc_debug_class_hash_ptr != 0 && objc_debug_class_hash_ptr != LLDB_INVALID_ADDRESS) { m_isa_hash_table_ptr = objc_debug_class_hash_ptr; } } } } } return m_isa_hash_table_ptr; }
virtual bool Execute (Args& command, CommandReturnObject &result) { Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; if (process == NULL) { result.AppendError("need a process to read memory"); result.SetStatus(eReturnStatusFailed); return false; } const size_t argc = command.GetArgumentCount(); if (m_options.m_infile) { if (argc < 1) { result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } } else if (argc < 2) { result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } StreamString buffer (Stream::eBinary, process->GetTarget().GetArchitecture().GetAddressByteSize(), process->GetTarget().GetArchitecture().GetByteOrder()); size_t item_byte_size = m_options.m_byte_size; lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0); if (addr == LLDB_INVALID_ADDRESS) { result.AppendErrorWithFormat("Invalid address string '%s'.\n", command.GetArgumentAtIndex(0)); result.SetStatus(eReturnStatusFailed); return false; } if (m_options.m_infile) { size_t length = SIZE_MAX; if (m_options.m_byte_size > 0) length = m_options.m_byte_size; lldb::DataBufferSP data_sp (m_options.m_infile.ReadFileContents (m_options.m_infile_offset, length)); if (data_sp) { length = data_sp->GetByteSize(); if (length > 0) { Error error; size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error); if (bytes_written == length) { // All bytes written result.GetOutputStream().Printf("%zu bytes were written to 0x%llx\n", bytes_written, addr); result.SetStatus(eReturnStatusSuccessFinishResult); } else if (bytes_written > 0) { // Some byte written result.GetOutputStream().Printf("%zu bytes of %zu requested were written to 0x%llx\n", bytes_written, length, addr); result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); result.SetStatus(eReturnStatusFailed); } } } else { result.AppendErrorWithFormat ("Unable to read contents of file.\n"); result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } else if (m_options.m_byte_size == 0) { if (m_options.m_format == eFormatPointer) item_byte_size = buffer.GetAddressByteSize(); else item_byte_size = 1; } command.Shift(); // shift off the address argument uint64_t uval64; int64_t sval64; bool success = false; const uint32_t num_value_args = command.GetArgumentCount(); uint32_t i; for (i=0; i<num_value_args; ++i) { const char *value_str = command.GetArgumentAtIndex(i); switch (m_options.m_format) { case eFormatFloat: // TODO: add support for floats soon case eFormatCharPrintable: case eFormatBytesWithASCII: case eFormatComplex: case eFormatEnum: case eFormatUnicode16: case eFormatUnicode32: case eFormatVectorOfChar: case eFormatVectorOfSInt8: case eFormatVectorOfUInt8: case eFormatVectorOfSInt16: case eFormatVectorOfUInt16: case eFormatVectorOfSInt32: case eFormatVectorOfUInt32: case eFormatVectorOfSInt64: case eFormatVectorOfUInt64: case eFormatVectorOfFloat32: case eFormatVectorOfFloat64: case eFormatVectorOfUInt128: result.AppendError("unsupported format for writing memory"); result.SetStatus(eReturnStatusFailed); return false; case eFormatDefault: case eFormatBytes: case eFormatHex: case eFormatPointer: // Decode hex bytes uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success); if (!success) { result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str); result.SetStatus(eReturnStatusFailed); return false; } else if (!UIntValueIsValidForSize (uval64, item_byte_size)) { result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); result.SetStatus(eReturnStatusFailed); return false; } buffer.PutMaxHex64 (uval64, item_byte_size); break; case eFormatBoolean: uval64 = Args::StringToBoolean(value_str, false, &success); if (!success) { result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str); result.SetStatus(eReturnStatusFailed); return false; } buffer.PutMaxHex64 (uval64, item_byte_size); break; case eFormatBinary: uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success); if (!success) { result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str); result.SetStatus(eReturnStatusFailed); return false; } else if (!UIntValueIsValidForSize (uval64, item_byte_size)) { result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); result.SetStatus(eReturnStatusFailed); return false; } buffer.PutMaxHex64 (uval64, item_byte_size); break; case eFormatChar: case eFormatCString: if (value_str[0]) { size_t len = strlen (value_str); // Include the NULL for C strings... if (m_options.m_format == eFormatCString) ++len; Error error; if (process->WriteMemory (addr, value_str, len, error) == len) { addr += len; } else { result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); result.SetStatus(eReturnStatusFailed); return false; } } break; case eFormatDecimal: sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success); if (!success) { result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str); result.SetStatus(eReturnStatusFailed); return false; } else if (!SIntValueIsValidForSize (sval64, item_byte_size)) { result.AppendErrorWithFormat ("Value %lli is too large or small to fit in a %u byte signed integer value.\n", sval64, item_byte_size); result.SetStatus(eReturnStatusFailed); return false; } buffer.PutMaxHex64 (sval64, item_byte_size); break; case eFormatUnsigned: uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success); if (!success) { result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str); result.SetStatus(eReturnStatusFailed); return false; } else if (!UIntValueIsValidForSize (uval64, item_byte_size)) { result.AppendErrorWithFormat ("Value %llu is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); result.SetStatus(eReturnStatusFailed); return false; } buffer.PutMaxHex64 (uval64, item_byte_size); break; case eFormatOctal: uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success); if (!success) { result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str); result.SetStatus(eReturnStatusFailed); return false; } else if (!UIntValueIsValidForSize (uval64, item_byte_size)) { result.AppendErrorWithFormat ("Value %llo is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); result.SetStatus(eReturnStatusFailed); return false; } buffer.PutMaxHex64 (uval64, item_byte_size); break; } } if (!buffer.GetString().empty()) { Error error; if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size()) return true; else { result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); result.SetStatus(eReturnStatusFailed); return false; } } return true; }
virtual bool Execute (Args& command, CommandReturnObject &result) { Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; if (process == NULL) { result.AppendError("need a process to read memory"); result.SetStatus(eReturnStatusFailed); return false; } const size_t argc = command.GetArgumentCount(); if (argc == 0 || argc > 2) { result.AppendErrorWithFormat ("%s takes 1 or two args.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } size_t item_byte_size = m_options.m_byte_size; if (item_byte_size == 0) { if (m_options.m_format == eFormatPointer) item_byte_size = process->GetTarget().GetArchitecture().GetAddressByteSize(); else item_byte_size = 1; } size_t item_count = m_options.m_count; size_t num_per_line = m_options.m_num_per_line; if (num_per_line == 0) { num_per_line = (16/item_byte_size); if (num_per_line == 0) num_per_line = 1; } size_t total_byte_size = m_options.m_count * item_byte_size; if (total_byte_size == 0) total_byte_size = 32; lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0); if (addr == LLDB_INVALID_ADDRESS) { result.AppendErrorWithFormat("invalid start address string '%s'.\n", command.GetArgumentAtIndex(0)); result.SetStatus(eReturnStatusFailed); return false; } if (argc == 2) { lldb::addr_t end_addr = Args::StringToUInt64(command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0); if (end_addr == LLDB_INVALID_ADDRESS) { result.AppendErrorWithFormat("Invalid end address string '%s'.\n", command.GetArgumentAtIndex(1)); result.SetStatus(eReturnStatusFailed); return false; } else if (end_addr <= addr) { result.AppendErrorWithFormat("End address (0x%llx) must be greater that the start address (0x%llx).\n", end_addr, addr); result.SetStatus(eReturnStatusFailed); return false; } else if (item_count != 0) { result.AppendErrorWithFormat("Specify either the end address (0x%llx) or the count (--count %u), not both.\n", end_addr, item_count); result.SetStatus(eReturnStatusFailed); return false; } total_byte_size = end_addr - addr; item_count = total_byte_size / item_byte_size; } else { if (item_count == 0) item_count = 32; } DataBufferSP data_sp(new DataBufferHeap (total_byte_size, '\0')); Error error; size_t bytes_read = process->ReadMemory(addr, data_sp->GetBytes (), data_sp->GetByteSize(), error); if (bytes_read == 0) { result.AppendWarningWithFormat("Read from 0x%llx failed.\n", addr); result.AppendError(error.AsCString()); result.SetStatus(eReturnStatusFailed); return false; } if (bytes_read < total_byte_size) result.AppendWarningWithFormat("Not all bytes (%u/%u) were able to be read from 0x%llx.\n", bytes_read, total_byte_size, addr); result.SetStatus(eReturnStatusSuccessFinishResult); DataExtractor data (data_sp, process->GetTarget().GetArchitecture().GetByteOrder(), process->GetTarget().GetArchitecture().GetAddressByteSize()); StreamFile outfile_stream; Stream *output_stream = NULL; if (m_options.m_outfile_filespec) { char path[PATH_MAX]; m_options.m_outfile_filespec.GetPath (path, sizeof(path)); char mode[16] = { 'w', '\0' }; if (m_options.m_append_to_outfile) mode[0] = 'a'; if (outfile_stream.GetFile ().Open (path, File::eOpenOptionWrite | File::eOpenOptionCanCreate).Success()) { if (m_options.m_output_as_binary) { int bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read); if (bytes_written > 0) { result.GetOutputStream().Printf ("%i bytes %s to '%s'\n", bytes_written, m_options.m_append_to_outfile ? "appended" : "written", path); return true; } else { result.AppendErrorWithFormat("Failed to write %zu bytes to '%s'.\n", bytes_read, path); result.SetStatus(eReturnStatusFailed); return false; } } else { // We are going to write ASCII to the file just point the // output_stream to our outfile_stream... output_stream = &outfile_stream; } } else { result.AppendErrorWithFormat("Failed to open file '%s' with a mode of '%s'.\n", path, mode); result.SetStatus(eReturnStatusFailed); return false; } } else { output_stream = &result.GetOutputStream(); } assert (output_stream); data.Dump (output_stream, 0, m_options.m_format, item_byte_size, item_count, num_per_line, addr, 0, 0); output_stream->EOL(); return true; }
Error Value::GetValueAsData (ExecutionContext *exe_ctx, clang::ASTContext *ast_context, DataExtractor &data, uint32_t data_offset, Module *module) { data.Clear(); Error error; lldb::addr_t address = LLDB_INVALID_ADDRESS; AddressType address_type = eAddressTypeFile; Address file_so_addr; switch (m_value_type) { default: error.SetErrorStringWithFormat("invalid value type %i", m_value_type); break; case eValueTypeScalar: data.SetByteOrder (lldb::endian::InlHostByteOrder()); if (m_context_type == eContextTypeClangType && ast_context) { uint32_t ptr_bit_width = ClangASTType::GetClangTypeBitWidth (ast_context, ClangASTContext::GetVoidPtrType(ast_context, false)); uint32_t ptr_byte_size = (ptr_bit_width + 7) / 8; data.SetAddressByteSize (ptr_byte_size); } else data.SetAddressByteSize(sizeof(void *)); if (m_value.GetData (data)) return error; // Success; error.SetErrorStringWithFormat("extracting data from value failed"); break; case eValueTypeLoadAddress: if (exe_ctx == NULL) { error.SetErrorString ("can't read load address (no execution context)"); } else { Process *process = exe_ctx->GetProcessPtr(); if (process == NULL) { error.SetErrorString ("can't read load address (invalid process)"); } else { address = m_value.ULongLong(LLDB_INVALID_ADDRESS); address_type = eAddressTypeLoad; data.SetByteOrder(process->GetTarget().GetArchitecture().GetByteOrder()); data.SetAddressByteSize(process->GetTarget().GetArchitecture().GetAddressByteSize()); } } break; case eValueTypeFileAddress: if (exe_ctx == NULL) { error.SetErrorString ("can't read file address (no execution context)"); } else if (exe_ctx->GetTargetPtr() == NULL) { error.SetErrorString ("can't read file address (invalid target)"); } else { address = m_value.ULongLong(LLDB_INVALID_ADDRESS); if (address == LLDB_INVALID_ADDRESS) { error.SetErrorString ("invalid file address"); } else { if (module == NULL) { // The only thing we can currently lock down to a module so that // we can resolve a file address, is a variable. Variable *variable = GetVariable(); if (variable) { SymbolContext var_sc; variable->CalculateSymbolContext(&var_sc); module = var_sc.module_sp.get(); } } if (module) { bool resolved = false; ObjectFile *objfile = module->GetObjectFile(); if (objfile) { Address so_addr(address, objfile->GetSectionList()); addr_t load_address = so_addr.GetLoadAddress (exe_ctx->GetTargetPtr()); bool process_launched_and_stopped = exe_ctx->GetProcessPtr() ? StateIsStoppedState(exe_ctx->GetProcessPtr()->GetState(), true /* must_exist */) : false; // Don't use the load address if the process has exited. if (load_address != LLDB_INVALID_ADDRESS && process_launched_and_stopped) { resolved = true; address = load_address; address_type = eAddressTypeLoad; data.SetByteOrder(exe_ctx->GetTargetRef().GetArchitecture().GetByteOrder()); data.SetAddressByteSize(exe_ctx->GetTargetRef().GetArchitecture().GetAddressByteSize()); } else { if (so_addr.IsSectionOffset()) { resolved = true; file_so_addr = so_addr; data.SetByteOrder(objfile->GetByteOrder()); data.SetAddressByteSize(objfile->GetAddressByteSize()); } } } if (!resolved) { Variable *variable = GetVariable(); if (module) { if (variable) error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%llx for variable '%s' in %s%s%s", address, variable->GetName().AsCString(""), module->GetFileSpec().GetDirectory().GetCString(), module->GetFileSpec().GetDirectory() ? "/" : "", module->GetFileSpec().GetFilename().GetCString()); else error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%llx in %s%s%s", address, module->GetFileSpec().GetDirectory().GetCString(), module->GetFileSpec().GetDirectory() ? "/" : "", module->GetFileSpec().GetFilename().GetCString()); } else { if (variable) error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%llx for variable '%s'", address, variable->GetName().AsCString("")); else error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%llx", address); } } } else { // Can't convert a file address to anything valid without more // context (which Module it came from) error.SetErrorString ("can't read memory from file address without more context"); } } } break; case eValueTypeHostAddress: address = m_value.ULongLong(LLDB_INVALID_ADDRESS); address_type = eAddressTypeHost; if (exe_ctx) { Target *target = exe_ctx->GetTargetPtr(); if (target) { data.SetByteOrder(target->GetArchitecture().GetByteOrder()); data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); break; } } // fallback to host settings data.SetByteOrder(lldb::endian::InlHostByteOrder()); data.SetAddressByteSize(sizeof(void *)); break; } // Bail if we encountered any errors if (error.Fail()) return error; if (address == LLDB_INVALID_ADDRESS) { error.SetErrorStringWithFormat ("invalid %s address", address_type == eAddressTypeHost ? "host" : "load"); return error; } // If we got here, we need to read the value from memory uint32_t byte_size = GetValueByteSize (ast_context, &error); // Bail if we encountered any errors getting the byte size if (error.Fail()) return error; // Make sure we have enough room within "data", and if we don't make // something large enough that does if (!data.ValidOffsetForDataOfSize (data_offset, byte_size)) { DataBufferSP data_sp(new DataBufferHeap (data_offset + byte_size, '\0')); data.SetData(data_sp); } uint8_t* dst = const_cast<uint8_t*>(data.PeekData (data_offset, byte_size)); if (dst != NULL) { if (address_type == eAddressTypeHost) { // The address is an address in this process, so just copy it memcpy (dst, (uint8_t*)NULL + address, byte_size); } else if ((address_type == eAddressTypeLoad) || (address_type == eAddressTypeFile)) { if (file_so_addr.IsValid()) { // We have a file address that we were able to translate into a // section offset address so we might be able to read this from // the object files if we don't have a live process. Lets always // try and read from the process if we have one though since we // want to read the actual value by setting "prefer_file_cache" // to false. const bool prefer_file_cache = false; if (exe_ctx->GetTargetRef().ReadMemory(file_so_addr, prefer_file_cache, dst, byte_size, error) != byte_size) { error.SetErrorStringWithFormat("read memory from 0x%llx failed", (uint64_t)address); } } else { // The execution context might have a NULL process, but it // might have a valid process in the exe_ctx->target, so use // the ExecutionContext::GetProcess accessor to ensure we // get the process if there is one. Process *process = exe_ctx->GetProcessPtr(); if (process) { const size_t bytes_read = process->ReadMemory(address, dst, byte_size, error); if (bytes_read != byte_size) error.SetErrorStringWithFormat("read memory from 0x%llx failed (%u of %u bytes read)", (uint64_t)address, (uint32_t)bytes_read, (uint32_t)byte_size); } else { error.SetErrorStringWithFormat("read memory from 0x%llx failed (invalid process)", (uint64_t)address); } } } else { error.SetErrorStringWithFormat ("unsupported AddressType value (%i)", address_type); } } else { error.SetErrorStringWithFormat ("out of memory"); } return error; }
lldb::ExpressionResults UserExpression::Evaluate (ExecutionContext &exe_ctx, const EvaluateExpressionOptions& options, const char *expr_cstr, const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp, Error &error, uint32_t line_offset, lldb::ModuleSP *jit_module_sp_ptr) { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy(); lldb::LanguageType language = options.GetLanguage(); const ResultType desired_type = options.DoesCoerceToId() ? UserExpression::eResultTypeId : UserExpression::eResultTypeAny; lldb::ExpressionResults execution_results = lldb::eExpressionSetupError; Target *target = exe_ctx.GetTargetPtr(); if (!target) { if (log) log->Printf("== [UserExpression::Evaluate] Passed a NULL target, can't run expressions."); return lldb::eExpressionSetupError; } Process *process = exe_ctx.GetProcessPtr(); if (process == NULL || process->GetState() != lldb::eStateStopped) { if (execution_policy == eExecutionPolicyAlways) { if (log) log->Printf("== [UserExpression::Evaluate] Expression may not run, but is not constant =="); error.SetErrorString ("expression needed to run but couldn't"); return execution_results; } } if (process == NULL || !process->CanJIT()) execution_policy = eExecutionPolicyNever; const char *full_prefix = NULL; const char *option_prefix = options.GetPrefix(); std::string full_prefix_storage; if (expr_prefix && option_prefix) { full_prefix_storage.assign(expr_prefix); full_prefix_storage.append(option_prefix); if (!full_prefix_storage.empty()) full_prefix = full_prefix_storage.c_str(); } else if (expr_prefix) full_prefix = expr_prefix; else full_prefix = option_prefix; // If the language was not specified in the expression command, // set it to the language in the target's properties if // specified, else default to the langage for the frame. if (language == lldb::eLanguageTypeUnknown) { if (target->GetLanguage() != lldb::eLanguageTypeUnknown) language = target->GetLanguage(); else if (StackFrame *frame = exe_ctx.GetFramePtr()) language = frame->GetLanguage(); } // If the language was not specified in the expression command, // set it to the language in the target's properties if // specified, else default to the langage for the frame. if (language == lldb::eLanguageTypeUnknown) { if (target->GetLanguage() != lldb::eLanguageTypeUnknown) language = target->GetLanguage(); else if (StackFrame *frame = exe_ctx.GetFramePtr()) language = frame->GetLanguage(); } lldb::UserExpressionSP user_expression_sp(target->GetUserExpressionForLanguage (expr_cstr, full_prefix, language, desired_type, options, error)); if (error.Fail()) { if (log) log->Printf ("== [UserExpression::Evaluate] Getting expression: %s ==", error.AsCString()); return lldb::eExpressionSetupError; } StreamString error_stream; if (log) log->Printf("== [UserExpression::Evaluate] Parsing expression %s ==", expr_cstr); const bool keep_expression_in_memory = true; const bool generate_debug_info = options.GetGenerateDebugInfo(); if (options.InvokeCancelCallback (lldb::eExpressionEvaluationParse)) { error.SetErrorString ("expression interrupted by callback before parse"); result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); return lldb::eExpressionInterrupted; } if (!user_expression_sp->Parse (error_stream, exe_ctx, execution_policy, keep_expression_in_memory, generate_debug_info, 0)) { execution_results = lldb::eExpressionParseError; if (error_stream.GetString().empty()) error.SetExpressionError (execution_results, "expression failed to parse, unknown error"); else error.SetExpressionError (execution_results, error_stream.GetString().c_str()); } else { // If a pointer to a lldb::ModuleSP was passed in, return the JIT'ed module if one was created if (jit_module_sp_ptr) *jit_module_sp_ptr = user_expression_sp->GetJITModule(); lldb::ExpressionVariableSP expr_result; if (execution_policy == eExecutionPolicyNever && !user_expression_sp->CanInterpret()) { if (log) log->Printf("== [UserExpression::Evaluate] Expression may not run, but is not constant =="); if (error_stream.GetString().empty()) error.SetExpressionError (lldb::eExpressionSetupError, "expression needed to run but couldn't"); } else { if (options.InvokeCancelCallback (lldb::eExpressionEvaluationExecution)) { error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback before execution"); result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); return lldb::eExpressionInterrupted; } error_stream.GetString().clear(); if (log) log->Printf("== [UserExpression::Evaluate] Executing expression =="); execution_results = user_expression_sp->Execute (error_stream, exe_ctx, options, user_expression_sp, expr_result); if (options.GetResultIsInternal() && expr_result && process) { process->GetTarget().GetPersistentExpressionStateForLanguage(language)->RemovePersistentVariable (expr_result); } if (execution_results != lldb::eExpressionCompleted) { if (log) log->Printf("== [UserExpression::Evaluate] Execution completed abnormally =="); if (error_stream.GetString().empty()) error.SetExpressionError (execution_results, "expression failed to execute, unknown error"); else error.SetExpressionError (execution_results, error_stream.GetString().c_str()); } else { if (expr_result) { result_valobj_sp = expr_result->GetValueObject(); if (log) log->Printf("== [UserExpression::Evaluate] Execution completed normally with result %s ==", result_valobj_sp->GetValueAsCString()); } else { if (log) log->Printf("== [UserExpression::Evaluate] Execution completed normally with no result =="); error.SetError(UserExpression::kNoResult, lldb::eErrorTypeGeneric); } } } } if (options.InvokeCancelCallback(lldb::eExpressionEvaluationComplete)) { error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback after complete"); return lldb::eExpressionInterrupted; } if (result_valobj_sp.get() == NULL) { result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); } return execution_results; }
// 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(); }
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; }