diff options
Diffstat (limited to 'lldb/source/Expression')
-rw-r--r-- | lldb/source/Expression/ClangExpressionParser.cpp | 5 | ||||
-rw-r--r-- | lldb/source/Expression/ClangFunction.cpp | 1 | ||||
-rw-r--r-- | lldb/source/Expression/ClangUserExpression.cpp | 1 | ||||
-rw-r--r-- | lldb/source/Expression/ClangUtilityFunction.cpp | 3 | ||||
-rw-r--r-- | lldb/source/Expression/IRExecutionUnit.cpp | 536 | ||||
-rw-r--r-- | lldb/source/Expression/IRMemoryMap.cpp | 410 |
6 files changed, 642 insertions, 314 deletions
diff --git a/lldb/source/Expression/ClangExpressionParser.cpp b/lldb/source/Expression/ClangExpressionParser.cpp index 32daaa92861..61e24101491 100644 --- a/lldb/source/Expression/ClangExpressionParser.cpp +++ b/lldb/source/Expression/ClangExpressionParser.cpp @@ -461,7 +461,8 @@ static bool FindFunctionInModule (ConstString &mangled_name, Error ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, - lldb::addr_t &func_end, + lldb::addr_t &func_end, + std::auto_ptr<IRExecutionUnit> &execution_unit_ap, ExecutionContext &exe_ctx, bool &evaluated_statically, lldb::ClangExpressionVariableSP &const_result, @@ -593,6 +594,8 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, } m_execution_unit->GetRunnableInfo(err, func_addr, func_end); + + execution_unit_ap = m_execution_unit; return err; } diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp index f8db5c9c798..74fb0c0e806 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/ClangFunction.cpp @@ -266,6 +266,7 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) Error jit_error (m_parser->PrepareForExecution (m_jit_start_addr, m_jit_end_addr, + m_execution_unit_ap, exe_ctx, evaluated_statically, const_result, diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index cff35c35e7a..b0acfa04f23 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -463,6 +463,7 @@ ClangUserExpression::Parse (Stream &error_stream, Error jit_error = parser.PrepareForExecution (m_jit_start_addr, m_jit_end_addr, + m_execution_unit_ap, exe_ctx, m_evaluated_statically, m_const_result, diff --git a/lldb/source/Expression/ClangUtilityFunction.cpp b/lldb/source/Expression/ClangUtilityFunction.cpp index af33340bd16..61b0702dfd3 100644 --- a/lldb/source/Expression/ClangUtilityFunction.cpp +++ b/lldb/source/Expression/ClangUtilityFunction.cpp @@ -130,7 +130,8 @@ ClangUtilityFunction::Install (Stream &error_stream, bool evaluated_statically = false; // should stay that way Error jit_error = parser.PrepareForExecution (m_jit_start_addr, - m_jit_end_addr, + m_jit_end_addr, + m_execution_unit_ap, exe_ctx, evaluated_statically, const_result, diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index 25fb157040c..dba361bd525 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -1,4 +1,4 @@ -//===-- IRExecutionUnit.cpp ------------------------------*- C++ -*-===// +//===-- IRExecutionUnit.cpp -------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -29,7 +29,7 @@ IRExecutionUnit::IRExecutionUnit (std::auto_ptr<llvm::Module> &module_ap, ConstString &name, lldb::ProcessSP process_sp, std::vector<std::string> &cpu_features) : - m_process_wp(process_sp), + IRMemoryMap(process_sp), m_module_ap(module_ap), m_module(m_module_ap.get()), m_cpu_features(cpu_features), @@ -45,89 +45,55 @@ IRExecutionUnit::WriteNow (const uint8_t *bytes, size_t size, Error &error) { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - auto iter = m_allocations.insert(m_allocations.end(), Allocation()); - - Allocation &allocation(*iter); - - allocation.m_size = size; - allocation.m_alignment = 8; - allocation.m_data.reset(new DataBufferHeap(bytes, size)); - allocation.m_local_start = (uintptr_t)allocation.m_data->GetBytes(); - allocation.m_section_id = Allocation::eSectionIDNone; - - lldb_private::Error err; - - size_t allocation_size = (allocation.m_size ? allocation.m_size : 1) + allocation.m_alignment - 1; - - if (allocation_size == 0) - allocation_size = 1; - - lldb::ProcessSP process_sp = m_process_wp.lock(); - - if (!process_sp) - { - err.SetErrorToGenericError(); - err.SetErrorString("Couldn't find the process"); - return LLDB_INVALID_ADDRESS; - } - - allocation.m_remote_allocation = process_sp->AllocateMemory(allocation_size, - (lldb::ePermissionsReadable | lldb::ePermissionsWritable), - err); + lldb::addr_t allocation_process_addr = Malloc (size, + 8, + lldb::ePermissionsWritable | lldb::ePermissionsReadable, + eAllocationPolicyMirror, + error); - if (!err.Success()) + if (!error.Success()) return LLDB_INVALID_ADDRESS; - process_sp->WriteMemory(allocation.m_remote_allocation, bytes, size, err); + WriteMemory(allocation_process_addr, bytes, size, error); - if (!err.Success()) + if (!error.Success()) { - process_sp->DeallocateMemory(allocation.m_remote_allocation); - allocation.m_remote_allocation = LLDB_INVALID_ADDRESS; + Error err; + Free (allocation_process_addr, err); + return LLDB_INVALID_ADDRESS; } - uint64_t mask = allocation.m_alignment - 1; - - allocation.m_remote_start = (allocation.m_remote_allocation + mask) & (~mask); - - allocation.m_allocated = true; - - if (log) + if (Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)) { - log->Printf("IRExecutionUnit::WriteNow() wrote to 0x%llx", allocation.m_remote_start); - allocation.dump(log); - } + DataBufferHeap my_buffer(size, 0); + Error err; + ReadMemory(my_buffer.GetBytes(), allocation_process_addr, size, err); - return allocation.m_remote_start; + if (err.Success()) + { + DataExtractor my_extractor(my_buffer.GetBytes(), my_buffer.GetByteSize(), lldb::eByteOrderBig, 8); + + StreamString ss; + + my_extractor.Dump(&ss, 0, lldb::eFormatBytesWithASCII, 1, my_buffer.GetByteSize(), 32, allocation_process_addr, 0, 0); + + log->PutCString(ss.GetData()); + } + } + + return allocation_process_addr; } void IRExecutionUnit::FreeNow (lldb::addr_t allocation) { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - if (allocation == LLDB_INVALID_ADDRESS) return; - lldb::ProcessSP process_sp = m_process_wp.lock(); - - if (!process_sp) - return; + Error err; - for (auto ai = m_allocations.begin(), ae = m_allocations.end(); - ai != ae; - ++ai) - { - if (ai->m_remote_allocation == allocation) - { - m_allocations.erase(ai); - log->Printf("IRExecutionUnit::FreeNow() freed 0x%llx", allocation); - return; - } - } + Free(allocation, err); } Error @@ -271,7 +237,7 @@ IRExecutionUnit::GetRunnableInfo(Error &error, lldb::addr_t &func_addr, lldb::addr_t &func_end) { - lldb::ProcessSP process_sp(m_process_wp.lock()); + lldb::ProcessSP process_sp(GetProcessWP().lock()); func_addr = LLDB_INVALID_ADDRESS; func_end = LLDB_INVALID_ADDRESS; @@ -289,159 +255,147 @@ IRExecutionUnit::GetRunnableInfo(Error &error, func_end = m_function_end_load_addr; return; - }; // someone else may have gotten the mutex first + }; + + m_did_jit = true; + + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + std::string error_string; + if (log) { - Mutex::Locker jit_mutex_locker(m_jit_mutex); - - if (m_did_jit) - { - func_addr = m_function_load_addr; - func_end = m_function_end_load_addr; - - return; - }; // someone else may have gotten the mutex first + std::string s; + llvm::raw_string_ostream oss(s); - m_did_jit = true; + m_module->print(oss, NULL); - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + oss.flush(); - std::string error_string; - - if (log) - { - std::string s; - llvm::raw_string_ostream oss(s); - - m_module->print(oss, NULL); - - oss.flush(); + log->Printf ("Module being sent to JIT: \n%s", s.c_str()); + } + + llvm::Triple triple(m_module->getTargetTriple()); + llvm::Function *function = m_module->getFunction (m_name.AsCString()); + llvm::Reloc::Model relocModel; + llvm::CodeModel::Model codeModel; + + if (triple.isOSBinFormatELF()) + { + relocModel = llvm::Reloc::Static; + // This will be small for 32-bit and large for 64-bit. + codeModel = llvm::CodeModel::JITDefault; + } + else + { + relocModel = llvm::Reloc::PIC_; + codeModel = llvm::CodeModel::Small; + } + + m_module_ap->getContext().setInlineAsmDiagnosticHandler(ReportInlineAsmError, &error); + + llvm::EngineBuilder builder(m_module_ap.get()); + + builder.setEngineKind(llvm::EngineKind::JIT) + .setErrorStr(&error_string) + .setRelocationModel(relocModel) + .setJITMemoryManager(new MemoryManager(*this)) + .setOptLevel(llvm::CodeGenOpt::Less) + .setAllocateGVsWithCode(true) + .setCodeModel(codeModel) + .setUseMCJIT(true); + + llvm::StringRef mArch; + llvm::StringRef mCPU; + llvm::SmallVector<std::string, 0> mAttrs; + + for (std::string &feature : m_cpu_features) + mAttrs.push_back(feature); + + llvm::TargetMachine *target_machine = builder.selectTarget(triple, + mArch, + mCPU, + mAttrs); + + m_execution_engine_ap.reset(builder.create(target_machine)); + + if (!m_execution_engine_ap.get()) + { + error.SetErrorToGenericError(); + error.SetErrorStringWithFormat("Couldn't JIT the function: %s", error_string.c_str()); + return; + } + else + { + m_module_ap.release(); // ownership was transferred + } + + m_execution_engine_ap->DisableLazyCompilation(); + + // We don't actually need the function pointer here, this just forces it to get resolved. + + void *fun_ptr = m_execution_engine_ap->getPointerToFunction(function); + + if (!error.Success()) + { + // We got an error through our callback! + return; + } + + if (!function) + { + error.SetErrorToGenericError(); + error.SetErrorStringWithFormat("Couldn't find '%s' in the JITted module", m_name.AsCString()); + return; + } + + if (!fun_ptr) + { + error.SetErrorToGenericError(); + error.SetErrorStringWithFormat("'%s' was in the JITted module but wasn't lowered", m_name.AsCString()); + return; + } + + m_jitted_functions.push_back (JittedFunction(m_name.AsCString(), (lldb::addr_t)fun_ptr)); + + CommitAllocations(process_sp); + ReportAllocations(*m_execution_engine_ap); + WriteData(process_sp); - log->Printf ("Module being sent to JIT: \n%s", s.c_str()); - } - - llvm::Triple triple(m_module->getTargetTriple()); - llvm::Function *function = m_module->getFunction (m_name.AsCString()); - llvm::Reloc::Model relocModel; - llvm::CodeModel::Model codeModel; + for (JittedFunction &jitted_function : m_jitted_functions) + { + jitted_function.m_remote_addr = GetRemoteAddressForLocal (jitted_function.m_local_addr); - if (triple.isOSBinFormatELF()) + if (!jitted_function.m_name.compare(m_name.AsCString())) { - relocModel = llvm::Reloc::Static; - // This will be small for 32-bit and large for 64-bit. - codeModel = llvm::CodeModel::JITDefault; + AddrRange func_range = GetRemoteRangeForLocal(jitted_function.m_local_addr); + m_function_end_load_addr = func_range.first + func_range.second; + m_function_load_addr = jitted_function.m_remote_addr; } - else - { - relocModel = llvm::Reloc::PIC_; - codeModel = llvm::CodeModel::Small; - } - - m_module_ap->getContext().setInlineAsmDiagnosticHandler(ReportInlineAsmError, &error); - - llvm::EngineBuilder builder(m_module_ap.get()); - - builder.setEngineKind(llvm::EngineKind::JIT) - .setErrorStr(&error_string) - .setRelocationModel(relocModel) - .setJITMemoryManager(new MemoryManager(*this)) - .setOptLevel(llvm::CodeGenOpt::Less) - .setAllocateGVsWithCode(true) - .setCodeModel(codeModel) - .setUseMCJIT(true); - - llvm::StringRef mArch; - llvm::StringRef mCPU; - llvm::SmallVector<std::string, 0> mAttrs; - - for (std::string &feature : m_cpu_features) - mAttrs.push_back(feature); + } + + if (log) + { + log->Printf("Code can be run in the target."); - llvm::TargetMachine *target_machine = builder.selectTarget(triple, - mArch, - mCPU, - mAttrs); + StreamString disassembly_stream; - m_execution_engine_ap.reset(builder.create(target_machine)); + Error err = DisassembleFunction(disassembly_stream, process_sp); - if (!m_execution_engine_ap.get()) + if (!err.Success()) { - error.SetErrorToGenericError(); - error.SetErrorStringWithFormat("Couldn't JIT the function: %s", error_string.c_str()); - return; + log->Printf("Couldn't disassemble function : %s", err.AsCString("unknown error")); } else { - m_module_ap.release(); // ownership was transferred - } - - m_execution_engine_ap->DisableLazyCompilation(); - - // We don't actually need the function pointer here, this just forces it to get resolved. - - void *fun_ptr = m_execution_engine_ap->getPointerToFunction(function); - - if (!error.Success()) - { - // We got an error through our callback! - return; - } - - if (!function) - { - error.SetErrorToGenericError(); - error.SetErrorStringWithFormat("Couldn't find '%s' in the JITted module", m_name.AsCString()); - return; + log->Printf("Function disassembly:\n%s", disassembly_stream.GetData()); } - - if (!fun_ptr) - { - error.SetErrorToGenericError(); - error.SetErrorStringWithFormat("'%s' was in the JITted module but wasn't lowered", m_name.AsCString()); - return; - } - - m_jitted_functions.push_back (JittedFunction(m_name.AsCString(), (lldb::addr_t)fun_ptr)); - - CommitAllocations(process_sp); - ReportAllocations(*m_execution_engine_ap); - WriteData(process_sp); - - for (JittedFunction &jitted_function : m_jitted_functions) - { - jitted_function.m_remote_addr = GetRemoteAddressForLocal (jitted_function.m_local_addr); - - if (!jitted_function.m_name.compare(m_name.AsCString())) - { - AddrRange func_range = GetRemoteRangeForLocal(jitted_function.m_local_addr); - m_function_end_load_addr = func_range.first + func_range.second; - m_function_load_addr = jitted_function.m_remote_addr; - } - } - - if (log) - { - log->Printf("Code can be run in the target."); - - StreamString disassembly_stream; - - Error err = DisassembleFunction(disassembly_stream, process_sp); - - if (!err.Success()) - { - log->Printf("Couldn't disassemble function : %s", err.AsCString("unknown error")); - } - else - { - log->Printf("Function disassembly:\n%s", disassembly_stream.GetData()); - } - } - - func_addr = m_function_load_addr; - func_end = m_function_end_load_addr; - - return; } + + func_addr = m_function_load_addr; + func_end = m_function_end_load_addr; + + return; } IRExecutionUnit::~IRExecutionUnit () @@ -482,20 +436,16 @@ IRExecutionUnit::MemoryManager::allocateStub(const llvm::GlobalValue* F, Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); uint8_t *return_value = m_default_mm_ap->allocateStub(F, StubSize, Alignment); - - auto iter = m_parent.m_allocations.insert(m_parent.m_allocations.end(), Allocation()); - - Allocation &allocation(*iter); - - allocation.m_size = StubSize; - allocation.m_alignment = Alignment; - allocation.m_local_start = (uintptr_t)return_value; + + m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + StubSize, + Alignment)); if (log) { log->Printf("IRExecutionUnit::allocateStub (F=%p, StubSize=%u, Alignment=%u) = %p", F, StubSize, Alignment, return_value); - allocation.dump(log); } return return_value; @@ -516,19 +466,15 @@ IRExecutionUnit::MemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) uint8_t *return_value = m_default_mm_ap->allocateSpace(Size, Alignment); - auto iter = m_parent.m_allocations.insert(m_parent.m_allocations.end(), Allocation()); - - Allocation &allocation(*iter); - - allocation.m_size = Size; - allocation.m_alignment = Alignment; - allocation.m_local_start = (uintptr_t)return_value; + m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + Size, + Alignment)); if (log) { log->Printf("IRExecutionUnit::allocateSpace(Size=%" PRIu64 ", Alignment=%u) = %p", (uint64_t)Size, Alignment, return_value); - allocation.dump(log); } return return_value; @@ -543,21 +489,16 @@ IRExecutionUnit::MemoryManager::allocateCodeSection(uintptr_t Size, uint8_t *return_value = m_default_mm_ap->allocateCodeSection(Size, Alignment, SectionID); - auto iter = m_parent.m_allocations.insert(m_parent.m_allocations.end(), Allocation()); - - Allocation &allocation(*iter); - - allocation.m_size = Size; - allocation.m_alignment = Alignment; - allocation.m_local_start = (uintptr_t)return_value; - allocation.m_section_id = SectionID; - allocation.m_executable = true; + m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value, + lldb::ePermissionsReadable | lldb::ePermissionsWritable | lldb::ePermissionsExecutable, + Size, + Alignment, + SectionID)); if (log) { log->Printf("IRExecutionUnit::allocateCodeSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p", (uint64_t)Size, Alignment, SectionID, return_value); - allocation.dump(log); } return return_value; @@ -573,20 +514,15 @@ IRExecutionUnit::MemoryManager::allocateDataSection(uintptr_t Size, uint8_t *return_value = m_default_mm_ap->allocateDataSection(Size, Alignment, SectionID, IsReadOnly); - auto iter = m_parent.m_allocations.insert(m_parent.m_allocations.end(), Allocation()); - - Allocation &allocation(*iter); - - allocation.m_size = Size; - allocation.m_alignment = Alignment; - allocation.m_local_start = (uintptr_t)return_value; - allocation.m_section_id = SectionID; - + m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + Size, + Alignment, + SectionID)); if (log) { log->Printf("IRExecutionUnit::allocateDataSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p", (uint64_t)Size, Alignment, SectionID, return_value); - allocation.dump(log); } return return_value; @@ -600,19 +536,15 @@ IRExecutionUnit::MemoryManager::allocateGlobal(uintptr_t Size, uint8_t *return_value = m_default_mm_ap->allocateGlobal(Size, Alignment); - auto iter = m_parent.m_allocations.insert(m_parent.m_allocations.end(), Allocation()); - - Allocation &allocation(*iter); - - allocation.m_size = Size; - allocation.m_alignment = Alignment; - allocation.m_local_start = (uintptr_t)return_value; + m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + Size, + Alignment)); if (log) { log->Printf("IRExecutionUnit::allocateGlobal(Size=0x%" PRIx64 ", Alignment=%u) = %p", (uint64_t)Size, Alignment, return_value); - allocation.dump(log); } return return_value; @@ -649,11 +581,16 @@ IRExecutionUnit::MemoryManager::deallocateExceptionTable(void *ET) lldb::addr_t IRExecutionUnit::GetRemoteAddressForLocal (lldb::addr_t local_address) { - for (Allocation &allocation : m_allocations) + for (AllocationRecord &record : m_records) { - if (local_address >= allocation.m_local_start && - local_address < allocation.m_local_start + allocation.m_size) - return allocation.m_remote_start + (local_address - allocation.m_local_start); + if (local_address >= record.m_host_address && + local_address < record.m_host_address + record.m_size) + { + if (record.m_process_address == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + } + + return record.m_process_address + (local_address - record.m_host_address); } return LLDB_INVALID_ADDRESS; @@ -662,11 +599,16 @@ IRExecutionUnit::GetRemoteAddressForLocal (lldb::addr_t local_address) IRExecutionUnit::AddrRange IRExecutionUnit::GetRemoteRangeForLocal (lldb::addr_t local_address) { - for (Allocation &allocation : m_allocations) + for (AllocationRecord &record : m_records) { - if (local_address >= allocation.m_local_start && - local_address < allocation.m_local_start + allocation.m_size) - return AddrRange(allocation.m_remote_start, allocation.m_size); + if (local_address >= record.m_host_address && + local_address < record.m_host_address + record.m_size) + { + if (record.m_process_address == LLDB_INVALID_ADDRESS) + return AddrRange(0, 0); + + return AddrRange(record.m_process_address, record.m_size); + } } return AddrRange (0, 0); @@ -675,53 +617,38 @@ IRExecutionUnit::GetRemoteRangeForLocal (lldb::addr_t local_address) bool IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp) { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - bool ret = true; - for (Allocation &allocation : m_allocations) + lldb_private::Error err; + + for (AllocationRecord &record : m_records) { - if (allocation.m_allocated) + if (record.m_process_address != LLDB_INVALID_ADDRESS) continue; - lldb_private::Error err; - - size_t allocation_size = (allocation.m_size ? allocation.m_size : 1) + allocation.m_alignment - 1; - - if (allocation_size == 0) - allocation_size = 1; - - allocation.m_remote_allocation = process_sp->AllocateMemory( - allocation_size, - allocation.m_executable ? (lldb::ePermissionsReadable | lldb::ePermissionsExecutable) - : (lldb::ePermissionsReadable | lldb::ePermissionsWritable), - err); - - uint64_t mask = allocation.m_alignment - 1; - allocation.m_remote_start = (allocation.m_remote_allocation + mask) & (~mask); + record.m_process_address = Malloc(record.m_size, + record.m_alignment, + record.m_permissions, + eAllocationPolicyProcessOnly, + err); if (!err.Success()) { ret = false; break; } - - allocation.m_allocated = true; - - if (log) - { - log->Printf("IRExecutionUnit::CommitAllocations() committed an allocation"); - allocation.dump(log); - } } if (!ret) { - for (Allocation &allocation : m_allocations) + for (AllocationRecord &record : m_records) { - if (allocation.m_allocated) - process_sp->DeallocateMemory(allocation.m_remote_start); + if (record.m_process_address != LLDB_INVALID_ADDRESS) + { + Free(record.m_process_address, err); + record.m_process_address = LLDB_INVALID_ADDRESS; + } } } @@ -731,16 +658,17 @@ IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp) void IRExecutionUnit::ReportAllocations (llvm::ExecutionEngine &engine) { - for (Allocation &allocation : m_allocations) + for (AllocationRecord &record : m_records) { - if (!allocation.m_allocated) + if (record.m_process_address == LLDB_INVALID_ADDRESS) continue; - if (allocation.m_section_id == Allocation::eSectionIDNone) + if (record.m_section_id == eSectionIDInvalid) continue; - engine.mapSectionAddress((void*)allocation.m_local_start, allocation.m_remote_start); + engine.mapSectionAddress((void*)record.m_host_address, record.m_process_address); } + // Trigger re-application of relocations. engine.finalizeObject(); } @@ -748,45 +676,29 @@ IRExecutionUnit::ReportAllocations (llvm::ExecutionEngine &engine) bool IRExecutionUnit::WriteData (lldb::ProcessSP &process_sp) { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - for (Allocation &allocation : m_allocations) + for (AllocationRecord &record : m_records) { - if (!allocation.m_allocated) + if (record.m_process_address == LLDB_INVALID_ADDRESS) return false; - if (allocation.m_local_start == LLDB_INVALID_ADDRESS) - continue; - lldb_private::Error err; - - if (process_sp->WriteMemory(allocation.m_remote_start, - (void*)allocation.m_local_start, - allocation.m_size, - err) != allocation.m_size || - !err.Success()) - return false; - - if (log) - { - log->Printf("IRExecutionUnit::CommitAllocations() wrote an allocation"); - allocation.dump(log); - } + + WriteMemory (record.m_process_address, (uint8_t*)record.m_host_address, record.m_size, err); } return true; } void -IRExecutionUnit::Allocation::dump (Log *log) +IRExecutionUnit::AllocationRecord::dump (Log *log) { if (!log) return; log->Printf("[0x%llx+0x%llx]->0x%llx (alignment %d, section ID %d)", - (unsigned long long)m_local_start, + (unsigned long long)m_host_address, (unsigned long long)m_size, - (unsigned long long)m_remote_start, + (unsigned long long)m_process_address, (unsigned)m_alignment, (unsigned)m_section_id); } diff --git a/lldb/source/Expression/IRMemoryMap.cpp b/lldb/source/Expression/IRMemoryMap.cpp new file mode 100644 index 00000000000..aea57b25ae1 --- /dev/null +++ b/lldb/source/Expression/IRMemoryMap.cpp @@ -0,0 +1,410 @@ +//===-- IRMemoryMap.cpp -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Expression/IRMemoryMap.h" +#include "lldb/Target/Process.h" + +using namespace lldb_private; + +IRMemoryMap::IRMemoryMap (lldb::ProcessSP process_sp) : + m_process_wp(process_sp) +{ +} + +IRMemoryMap::~IRMemoryMap () +{ + lldb::ProcessSP process_sp = m_process_wp.lock(); + + if (process_sp) + { + for (AllocationMap::value_type &allocation : m_allocations) + { + if (allocation.second.m_policy == eAllocationPolicyMirror || + allocation.second.m_policy == eAllocationPolicyHostOnly) + process_sp->DeallocateMemory(allocation.second.m_process_alloc); + + if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)) + { + log->Printf("IRMemoryMap::~IRMemoryMap deallocated [0x%llx..0x%llx)", + (uint64_t)allocation.second.m_process_start, + (uint64_t)allocation.second.m_process_start + (uint64_t)allocation.second.m_size); + } + } + } +} + +lldb::addr_t +IRMemoryMap::FindSpace (size_t size) +{ + // Yup, this is just plain O(n) insertion. We'll use a range tree if we + // start caring. + + lldb::addr_t remote_address = 0x1000; // skip first page of memory + + for (AllocationMap::value_type &allocation : m_allocations) + { + if (remote_address < allocation.second.m_process_start && + remote_address + size <= allocation.second.m_process_start) + return remote_address; + + remote_address = allocation.second.m_process_start = allocation.second.m_size; + } + + if (remote_address + size < remote_address) + return LLDB_INVALID_ADDRESS; // massively unlikely + + return remote_address; +} + +bool +IRMemoryMap::ContainsHostOnlyAllocations () +{ + for (AllocationMap::value_type &allocation : m_allocations) + { + if (allocation.second.m_policy == eAllocationPolicyHostOnly) + return true; + } + + return false; +} + +IRMemoryMap::AllocationMap::iterator +IRMemoryMap::FindAllocation (lldb::addr_t addr, size_t size) +{ + AllocationMap::iterator iter = m_allocations.lower_bound (addr); + + if (iter == m_allocations.end()) + return iter; + + if (iter->first > addr) + { + if (iter == m_allocations.begin()) + return m_allocations.end(); + iter--; + } + + if (iter->first <= addr && iter->first + iter->second.m_size >= addr + size) + return iter; + + return m_allocations.end(); +} + +lldb::addr_t +IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, AllocationPolicy policy, Error &error) +{ + lldb::ProcessSP process_sp; + lldb::addr_t allocation_address = LLDB_INVALID_ADDRESS; + lldb::addr_t aligned_address = LLDB_INVALID_ADDRESS; + + size_t allocation_size = (size ? size : 1) + alignment - 1; + + switch (policy) + { + default: + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't malloc: invalid allocation policy"); + return LLDB_INVALID_ADDRESS; + case eAllocationPolicyHostOnly: + allocation_address = FindSpace(allocation_size); + if (allocation_address == LLDB_INVALID_ADDRESS) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't malloc: address space is full"); + return LLDB_INVALID_ADDRESS; + } + break; + case eAllocationPolicyMirror: + if (ContainsHostOnlyAllocations()) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't malloc: host-only allocations are polluting the address space"); + return LLDB_INVALID_ADDRESS; + } + process_sp = m_process_wp.lock(); + if (process_sp) + { + allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error); + if (!error.Success()) + return LLDB_INVALID_ADDRESS; + } + else + { + allocation_address = FindSpace(allocation_size); + if (allocation_address == LLDB_INVALID_ADDRESS) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't malloc: address space is full"); + return LLDB_INVALID_ADDRESS; + } + } + break; + case eAllocationPolicyProcessOnly: + if (ContainsHostOnlyAllocations()) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't malloc: host-only allocations are polluting the address space"); + return LLDB_INVALID_ADDRESS; + } + process_sp = m_process_wp.lock(); + if (process_sp) + { + allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error); + if (!error.Success()) + return LLDB_INVALID_ADDRESS; + } + else + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't malloc: process doesn't exist, and this memory must be in the process"); + return LLDB_INVALID_ADDRESS; + } + break; + } + + + lldb::addr_t mask = alignment - 1; + aligned_address = (allocation_address + mask) & (~mask); + + Allocation &allocation(m_allocations[aligned_address]); + + allocation.m_process_alloc = allocation_address; + allocation.m_process_start = aligned_address; + allocation.m_size = size; + allocation.m_permissions = permissions; + allocation.m_alignment = alignment; + allocation.m_policy = policy; + + switch (policy) + { + default: + assert (0 && "We cannot reach this!"); + case eAllocationPolicyHostOnly: + allocation.m_data.reset(new DataBufferHeap(size, 0)); + break; + case eAllocationPolicyProcessOnly: + break; + case eAllocationPolicyMirror: + allocation.m_data.reset(new DataBufferHeap(size, 0)); + break; + } + + if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)) + { + const char * policy_string; + + switch (policy) + { + default: + policy_string = "<invalid policy>"; + break; + case eAllocationPolicyHostOnly: + policy_string = "eAllocationPolicyHostOnly"; + break; + case eAllocationPolicyProcessOnly: + policy_string = "eAllocationPolicyProcessOnly"; + break; + case eAllocationPolicyMirror: + policy_string = "eAllocationPolicyMirror"; + break; + } + + log->Printf("IRMemoryMap::Malloc (%llu, 0x%llx, 0x%llx, %s) -> 0x%llx", + (uint64_t)size, + (uint64_t)alignment, + (uint64_t)permissions, + policy_string, + aligned_address); + } + + return aligned_address; +} + +void +IRMemoryMap::Free (lldb::addr_t process_address, Error &error) +{ + AllocationMap::iterator iter = m_allocations.find(process_address); + + if (iter == m_allocations.end()) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't free: allocation doesn't exist"); + return; + } + + Allocation &allocation = iter->second; + + switch (allocation.m_policy) + { + default: + case eAllocationPolicyHostOnly: + break; + case eAllocationPolicyMirror: + case eAllocationPolicyProcessOnly: + lldb::ProcessSP process_sp = m_process_wp.lock(); + if (process_sp) + process_sp->DeallocateMemory(allocation.m_process_alloc); + } + + if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)) + { + log->Printf("IRMemoryMap::Free (0x%llx) freed [0x%llx..0x%llx)", + (uint64_t)process_address, + iter->second.m_process_start, + iter->second.m_process_start + iter->second.m_size); + } + + m_allocations.erase(iter); +} + +void +IRMemoryMap::WriteMemory (lldb::addr_t process_address, const uint8_t *bytes, size_t size, Error &error) +{ + AllocationMap::iterator iter = FindAllocation(process_address, size); + + if (iter == m_allocations.end()) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't write: no allocation contains the target range"); + return; + } + + Allocation &allocation = iter->second; + + uint64_t offset = process_address - allocation.m_process_start; + + lldb::ProcessSP process_sp; + + switch (allocation.m_policy) + { + default: + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't write: invalid allocation policy"); + return; + case eAllocationPolicyHostOnly: + if (!allocation.m_data) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't write: data buffer is empty"); + return; + } + ::memcpy (allocation.m_data->GetBytes() + offset, bytes, size); + break; + case eAllocationPolicyMirror: + if (!allocation.m_data) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't write: data buffer is empty"); + return; + } + ::memcpy (allocation.m_data->GetBytes() + offset, bytes, size); + process_sp = m_process_wp.lock(); + if (process_sp) + { + process_sp->WriteMemory(process_address, bytes, size, error); + if (!error.Success()) + return; + } + break; + case eAllocationPolicyProcessOnly: + process_sp = m_process_wp.lock(); + if (process_sp) + { + process_sp->WriteMemory(process_address, bytes, size, error); + if (!error.Success()) + return; + } + break; + } + + if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)) + { + log->Printf("IRMemoryMap::WriteMemory (0x%llx, 0x%llx, 0x%lld) went to [0x%llx..0x%llx)", + (uint64_t)process_address, + (uint64_t)bytes, + (uint64_t)size, + (uint64_t)allocation.m_process_start, + (uint64_t)allocation.m_process_start + (uint64_t)allocation.m_size); + } +} + +void +IRMemoryMap::ReadMemory (uint8_t *bytes, lldb::addr_t process_address, size_t size, Error &error) +{ + AllocationMap::iterator iter = FindAllocation(process_address, size); + + if (iter == m_allocations.end()) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't read: no allocation contains the target range"); + return; + } + + Allocation &allocation = iter->second; + + uint64_t offset = process_address - allocation.m_process_start; + + lldb::ProcessSP process_sp; + + switch (allocation.m_policy) + { + default: + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't read: invalid allocation policy"); + return; + case eAllocationPolicyHostOnly: + if (!allocation.m_data) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't read: data buffer is empty"); + return; + } + ::memcpy (bytes, allocation.m_data->GetBytes() + offset, size); + break; + case eAllocationPolicyMirror: + process_sp = m_process_wp.lock(); + if (process_sp) + { + process_sp->ReadMemory(process_address, bytes, size, error); + if (!error.Success()) + return; + } + else + { + if (!allocation.m_data) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't read: data buffer is empty"); + return; + } + ::memcpy (bytes, allocation.m_data->GetBytes() + offset, size); + } + break; + case eAllocationPolicyProcessOnly: + process_sp = m_process_wp.lock(); + if (process_sp) + { + process_sp->ReadMemory(process_address, bytes, size, error); + if (!error.Success()) + return; + } + break; + } + + if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)) + { + log->Printf("IRMemoryMap::ReadMemory (0x%llx, 0x%llx, 0x%lld) came from [0x%llx..0x%llx)", + (uint64_t)process_address, + (uint64_t)bytes, + (uint64_t)size, + (uint64_t)allocation.m_process_start, + (uint64_t)allocation.m_process_start + (uint64_t)allocation.m_size); + } +} |