| //===-- 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; | |
| } |