| //===-- InferiorCallPOSIX.cpp ---------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "InferiorCallPOSIX.h" |
| #include "lldb/Core/Address.h" |
| #include "lldb/Core/Module.h" |
| #include "lldb/Expression/DiagnosticManager.h" |
| #include "lldb/Host/Config.h" |
| #include "lldb/Symbol/SymbolContext.h" |
| #include "lldb/Symbol/TypeSystem.h" |
| #include "lldb/Target/ExecutionContext.h" |
| #include "lldb/Target/Platform.h" |
| #include "lldb/Target/Process.h" |
| #include "lldb/Target/Target.h" |
| #include "lldb/Target/ThreadPlanCallFunction.h" |
| #include "lldb/ValueObject/ValueObject.h" |
| |
| #if LLDB_ENABLE_POSIX |
| #include <sys/mman.h> |
| #else |
| // define them |
| #define PROT_NONE 0 |
| #define PROT_READ 1 |
| #define PROT_WRITE 2 |
| #define PROT_EXEC 4 |
| #endif |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| |
| /// Pick a call target from \p sc_list. A symbol from an ELF filter/auxiliary |
| /// library is resolved through its filtee(s) first, falling back to its own |
| /// definition only if none of them provide it, mirroring what the dynamic |
| /// linker does. |
| static Address GetCallableAddress(Target &target, |
| const SymbolContextList &sc_list) { |
| const uint32_t count = sc_list.GetSize(); |
| for (uint32_t i = 0; i < count; ++i) { |
| SymbolContext sc; |
| if (!sc_list.GetContextAtIndex(i, sc)) |
| continue; |
| if (sc.symbol) { |
| // Pass the containing module so all of its re-exported libraries |
| // (e.g. an ELF filter library's filtees) are searched in order. |
| if (Symbol *actual = |
| sc.symbol->ResolveReExportedSymbol(target, sc.module_sp)) |
| return actual->GetAddress(); |
| // A pure re-export placeholder with no filtee providing a definition |
| // has no code of its own and isn't callable. |
| if (sc.symbol->GetType() == eSymbolTypeReExported) |
| continue; |
| } |
| return sc.GetFunctionOrSymbolAddress(); |
| } |
| return Address(); |
| } |
| |
| bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, |
| addr_t addr, addr_t length, unsigned prot, |
| unsigned flags, addr_t fd, addr_t offset) { |
| Thread *thread = |
| process->GetThreadList().GetExpressionExecutionThread().get(); |
| if (thread == nullptr) |
| return false; |
| |
| ModuleFunctionSearchOptions function_options; |
| function_options.include_symbols = true; |
| function_options.include_inlines = false; |
| |
| SymbolContextList sc_list; |
| process->GetTarget().GetImages().FindFunctions( |
| ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list); |
| const uint32_t count = sc_list.GetSize(); |
| if (count > 0) { |
| EvaluateExpressionOptions options; |
| options.SetStopOthers(true); |
| options.SetUnwindOnError(true); |
| options.SetIgnoreBreakpoints(true); |
| options.SetTryAllThreads(true); |
| options.SetDebug(false); |
| options.SetTimeout(process->GetUtilityExpressionTimeout()); |
| options.SetTrapExceptions(false); |
| |
| addr_t prot_arg; |
| if (prot == eMmapProtNone) |
| prot_arg = PROT_NONE; |
| else { |
| prot_arg = 0; |
| if (prot & eMmapProtExec) |
| prot_arg |= PROT_EXEC; |
| if (prot & eMmapProtRead) |
| prot_arg |= PROT_READ; |
| if (prot & eMmapProtWrite) |
| prot_arg |= PROT_WRITE; |
| } |
| |
| Address mmap_addr = GetCallableAddress(process->GetTarget(), sc_list); |
| if (mmap_addr.IsValid()) { |
| auto type_system_or_err = |
| process->GetTarget().GetScratchTypeSystemForLanguage(eLanguageTypeC); |
| if (!type_system_or_err) { |
| llvm::consumeError(type_system_or_err.takeError()); |
| return false; |
| } |
| auto ts = *type_system_or_err; |
| if (!ts) |
| return false; |
| CompilerType void_ptr_type = |
| ts->GetBasicTypeFromAST(eBasicTypeVoid).GetPointerType(); |
| const ArchSpec arch = process->GetTarget().GetArchitecture(); |
| MmapArgList args = |
| process->GetTarget().GetPlatform()->GetMmapArgumentList( |
| arch, addr, length, prot_arg, flags, fd, offset); |
| lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallFunction( |
| *thread, mmap_addr, void_ptr_type, args, options)); |
| if (call_plan_sp) { |
| DiagnosticManager diagnostics; |
| |
| StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); |
| if (frame) { |
| ExecutionContext exe_ctx; |
| frame->CalculateExecutionContext(exe_ctx); |
| ExpressionResults result = process->RunThreadPlan( |
| exe_ctx, call_plan_sp, options, diagnostics); |
| if (result == eExpressionCompleted) { |
| |
| allocated_addr = |
| call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned( |
| LLDB_INVALID_ADDRESS); |
| if (process->GetAddressByteSize() == 4) { |
| if (allocated_addr == UINT32_MAX) |
| return false; |
| } else if (process->GetAddressByteSize() == 8) { |
| if (allocated_addr == UINT64_MAX) |
| return false; |
| } |
| return true; |
| } |
| } |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr, |
| addr_t length) { |
| Thread *thread = |
| process->GetThreadList().GetExpressionExecutionThread().get(); |
| if (thread == nullptr) |
| return false; |
| |
| ModuleFunctionSearchOptions function_options; |
| function_options.include_symbols = true; |
| function_options.include_inlines = false; |
| |
| SymbolContextList sc_list; |
| process->GetTarget().GetImages().FindFunctions( |
| ConstString("munmap"), eFunctionNameTypeFull, function_options, sc_list); |
| const uint32_t count = sc_list.GetSize(); |
| if (count > 0) { |
| EvaluateExpressionOptions options; |
| options.SetStopOthers(true); |
| options.SetUnwindOnError(true); |
| options.SetIgnoreBreakpoints(true); |
| options.SetTryAllThreads(true); |
| options.SetDebug(false); |
| options.SetTimeout(process->GetUtilityExpressionTimeout()); |
| options.SetTrapExceptions(false); |
| |
| Address munmap_addr = GetCallableAddress(process->GetTarget(), sc_list); |
| if (munmap_addr.IsValid()) { |
| lldb::addr_t args[] = {addr, length}; |
| lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallFunction( |
| *thread, munmap_addr, CompilerType(), args, options)); |
| if (call_plan_sp) { |
| DiagnosticManager diagnostics; |
| |
| StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); |
| if (frame) { |
| ExecutionContext exe_ctx; |
| frame->CalculateExecutionContext(exe_ctx); |
| ExpressionResults result = process->RunThreadPlan( |
| exe_ctx, call_plan_sp, options, diagnostics); |
| if (result == eExpressionCompleted) { |
| return true; |
| } |
| } |
| } |
| } |
| } |
| |
| return false; |
| } |