llvm-project/lldb/source/Expression/IRMemoryMap.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

847 lines
26 KiB
C++
Raw Normal View History

//===-- IRMemoryMap.cpp -----------------------------------------*- C++ -*-===//
//
// 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 "lldb/Expression/IRMemoryMap.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Scalar.h"
#include "lldb/Utility/Status.h"
using namespace lldb_private;
IRMemoryMap::IRMemoryMap(lldb::TargetSP target_sp) : m_target_wp(target_sp) {
if (target_sp)
m_process_wp = target_sp->GetProcessSP();
}
IRMemoryMap::~IRMemoryMap() {
lldb::ProcessSP process_sp = m_process_wp.lock();
if (process_sp) {
AllocationMap::iterator iter;
Status err;
while ((iter = m_allocations.begin()) != m_allocations.end()) {
err.Clear();
if (iter->second.m_leak)
m_allocations.erase(iter);
else
Free(iter->first, err);
}
}
}
lldb::addr_t IRMemoryMap::FindSpace(size_t size) {
// The FindSpace algorithm's job is to find a region of memory that the
// underlying process is unlikely to be using.
//
// The memory returned by this function will never be written to. The only
// point is that it should not shadow process memory if possible, so that
// expressions processing real values from the process do not use the wrong
// data.
//
// If the process can in fact allocate memory (CanJIT() lets us know this)
// then this can be accomplished just be allocating memory in the inferior.
// Then no guessing is required.
lldb::TargetSP target_sp = m_target_wp.lock();
lldb::ProcessSP process_sp = m_process_wp.lock();
const bool process_is_alive = process_sp && process_sp->IsAlive();
lldb::addr_t ret = LLDB_INVALID_ADDRESS;
if (size == 0)
return ret;
if (process_is_alive && process_sp->CanJIT()) {
Status alloc_error;
ret = process_sp->AllocateMemory(size, lldb::ePermissionsReadable |
lldb::ePermissionsWritable,
alloc_error);
if (!alloc_error.Success())
return LLDB_INVALID_ADDRESS;
else
return ret;
}
// At this point we know that we need to hunt.
//
// First, go to the end of the existing allocations we've made if there are
// any allocations. Otherwise start at the beginning of memory.
if (m_allocations.empty()) {
ret = 0x0;
} else {
auto back = m_allocations.rbegin();
lldb::addr_t addr = back->first;
size_t alloc_size = back->second.m_size;
ret = llvm::alignTo(addr + alloc_size, 4096);
}
// Now, if it's possible to use the GetMemoryRegionInfo API to detect mapped
// regions, walk forward through memory until a region is found that has
// adequate space for our allocation.
if (process_is_alive) {
const uint64_t end_of_memory = process_sp->GetAddressByteSize() == 8
? 0xffffffffffffffffull
: 0xffffffffull;
lldbassert(process_sp->GetAddressByteSize() == 4 ||
end_of_memory != 0xffffffffull);
MemoryRegionInfo region_info;
Status err = process_sp->GetMemoryRegionInfo(ret, region_info);
if (err.Success()) {
while (true) {
if (region_info.GetReadable() != MemoryRegionInfo::OptionalBool::eNo ||
region_info.GetWritable() != MemoryRegionInfo::OptionalBool::eNo ||
region_info.GetExecutable() !=
MemoryRegionInfo::OptionalBool::eNo) {
if (region_info.GetRange().GetRangeEnd() - 1 >= end_of_memory) {
ret = LLDB_INVALID_ADDRESS;
break;
} else {
ret = region_info.GetRange().GetRangeEnd();
}
} else if (ret + size < region_info.GetRange().GetRangeEnd()) {
return ret;
} else {
// ret stays the same. We just need to walk a bit further.
}
err = process_sp->GetMemoryRegionInfo(
region_info.GetRange().GetRangeEnd(), region_info);
if (err.Fail()) {
lldbassert(0 && "GetMemoryRegionInfo() succeeded, then failed");
ret = LLDB_INVALID_ADDRESS;
break;
}
}
}
}
// We've tried our algorithm, and it didn't work. Now we have to reset back
// to the end of the allocations we've already reported, or use a 'sensible'
// default if this is our first allocation.
if (m_allocations.empty()) {
uint32_t address_byte_size = GetAddressByteSize();
if (address_byte_size != UINT32_MAX) {
switch (address_byte_size) {
case 8:
ret = 0xffffffff00000000ull;
break;
case 4:
ret = 0xee000000ull;
break;
default:
break;
}
}
} else {
auto back = m_allocations.rbegin();
lldb::addr_t addr = back->first;
size_t alloc_size = back->second.m_size;
ret = llvm::alignTo(addr + alloc_size, 4096);
}
return ret;
}
IRMemoryMap::AllocationMap::iterator
IRMemoryMap::FindAllocation(lldb::addr_t addr, size_t size) {
This commit changes the way LLDB executes user expressions. Previously, ClangUserExpression assumed that if there was a constant result for an expression then it could be determined during parsing. In particular, the IRInterpreter ran while parser state (in particular, ClangExpressionDeclMap) was present. This approach is flawed, because the IRInterpreter actually is capable of using external variables, and hence the result might be different each run. Until now, we papered over this flaw by re-parsing the expression each time we ran it. I have rewritten the IRInterpreter to be completely independent of the ClangExpressionDeclMap. Instead of special-casing external variable lookup, which ties the IRInterpreter closely to LLDB, we now interpret the exact same IR that the JIT would see. This IR assumes that materialization has occurred; hence the recent implementation of the Materializer, which does not require parser state (in the form of ClangExpressionDeclMap) to be present. Materialization, interpretation, and dematerialization are now all independent of parsing. This means that in theory we can parse expressions once and run them many times. I have three outstanding tasks before shutting this down: - First, I will ensure that all of this works with core files. Core files have a Process but do not allow allocating memory, which currently confuses materialization. - Second, I will make expression breakpoint conditions remember their ClangUserExpression and re-use it. - Third, I will tear out all the redundant code (for example, materialization logic in ClangExpressionDeclMap) that is no longer used. While implementing this fix, I also found a bug in IRForTarget's handling of floating-point constants. This should be fixed. llvm-svn: 179801
2013-04-19 06:06:33 +08:00
if (addr == LLDB_INVALID_ADDRESS)
return m_allocations.end();
AllocationMap::iterator iter = m_allocations.lower_bound(addr);
if (iter == m_allocations.end() || 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();
}
bool IRMemoryMap::IntersectsAllocation(lldb::addr_t addr, size_t size) const {
if (addr == LLDB_INVALID_ADDRESS)
return false;
AllocationMap::const_iterator iter = m_allocations.lower_bound(addr);
// Since we only know that the returned interval begins at a location greater
// than or equal to where the given interval begins, it's possible that the
// given interval intersects either the returned interval or the previous
// interval. Thus, we need to check both. Note that we only need to check
// these two intervals. Since all intervals are disjoint it is not possible
// that an adjacent interval does not intersect, but a non-adjacent interval
// does intersect.
if (iter != m_allocations.end()) {
if (AllocationsIntersect(addr, size, iter->second.m_process_start,
iter->second.m_size))
return true;
}
if (iter != m_allocations.begin()) {
--iter;
if (AllocationsIntersect(addr, size, iter->second.m_process_start,
iter->second.m_size))
return true;
}
return false;
}
bool IRMemoryMap::AllocationsIntersect(lldb::addr_t addr1, size_t size1,
lldb::addr_t addr2, size_t size2) {
// Given two half open intervals [A, B) and [X, Y), the only 6 permutations
// that satisfy A<B and X<Y are the following:
// A B X Y
// A X B Y (intersects)
// A X Y B (intersects)
// X A B Y (intersects)
// X A Y B (intersects)
// X Y A B
// The first is B <= X, and the last is Y <= A. So the condition is !(B <= X
// || Y <= A)), or (X < B && A < Y)
return (addr2 < (addr1 + size1)) && (addr1 < (addr2 + size2));
}
lldb::ByteOrder IRMemoryMap::GetByteOrder() {
lldb::ProcessSP process_sp = m_process_wp.lock();
if (process_sp)
return process_sp->GetByteOrder();
lldb::TargetSP target_sp = m_target_wp.lock();
if (target_sp)
return target_sp->GetArchitecture().GetByteOrder();
return lldb::eByteOrderInvalid;
}
uint32_t IRMemoryMap::GetAddressByteSize() {
lldb::ProcessSP process_sp = m_process_wp.lock();
if (process_sp)
return process_sp->GetAddressByteSize();
lldb::TargetSP target_sp = m_target_wp.lock();
if (target_sp)
return target_sp->GetArchitecture().GetAddressByteSize();
return UINT32_MAX;
}
ExecutionContextScope *IRMemoryMap::GetBestExecutionContextScope() const {
lldb::ProcessSP process_sp = m_process_wp.lock();
if (process_sp)
return process_sp.get();
lldb::TargetSP target_sp = m_target_wp.lock();
if (target_sp)
return target_sp.get();
return nullptr;
}
IRMemoryMap::Allocation::Allocation(lldb::addr_t process_alloc,
lldb::addr_t process_start, size_t size,
uint32_t permissions, uint8_t alignment,
AllocationPolicy policy)
: m_process_alloc(process_alloc), m_process_start(process_start),
m_size(size), m_policy(policy), m_leak(false), m_permissions(permissions),
m_alignment(alignment) {
switch (policy) {
default:
llvm_unreachable("Invalid AllocationPolicy");
case eAllocationPolicyHostOnly:
case eAllocationPolicyMirror:
m_data.SetByteSize(size);
break;
case eAllocationPolicyProcessOnly:
break;
}
}
lldb::addr_t IRMemoryMap::Malloc(size_t size, uint8_t alignment,
uint32_t permissions, AllocationPolicy policy,
bool zero_memory, Status &error) {
lldb_private::Log *log(
lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
error.Clear();
lldb::ProcessSP process_sp;
lldb::addr_t allocation_address = LLDB_INVALID_ADDRESS;
lldb::addr_t aligned_address = LLDB_INVALID_ADDRESS;
size_t allocation_size;
if (size == 0) {
// FIXME: Malloc(0) should either return an invalid address or assert, in
// order to cut down on unnecessary allocations.
allocation_size = alignment;
} else {
// Round up the requested size to an aligned value.
allocation_size = llvm::alignTo(size, alignment);
// The process page cache does not see the requested alignment. We can't
// assume its result will be any more than 1-byte aligned. To work around
// this, request `alignment - 1` additional bytes.
allocation_size += 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:
process_sp = m_process_wp.lock();
LLDB_LOGF(log,
[lldb] Fix ARM32 inferior calls echo -e '#include <unistd.h>\nint main(void){\nsync();return 0;}'|./bin/clang -g -x c -;./bin/lldb -o 'file ./a.out' -o 'b main' -o r -o 'p (void)sync()' Actual: error: Expression can't be run, because there is no JIT compiled function Expected: <nothing, sync() has been executed> This patch has been checked by: D71707: clang-tidy: new bugprone-pointer-cast-widening https://reviews.llvm.org/D71707 Casting from 32-bit `void *` to `uint64_t` requires an intermediate `uintptr_t` cast otherwise the pointer gets sign-extended: echo -e '#include <stdio.h>\n#include <stdint.h>\nint main(void){void *p=(void *)0x80000000;unsigned long long ull=(unsigned long long)p;unsigned long long ull2=(unsigned long long)(uintptr_t)p;printf("p=%p ull=0x%llx ull2=0x%llx\\n",p,ull,ull2);return 0;}'|gcc -Wall -m32 -x c -;./a.out <stdin>: In function ‘main’: <stdin>:3:66: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] p=0x80000000 ull=0xffffffff80000000 ull2=0x80000000 With debug output: Actual: IRMemoryMap::WriteMemory (0xb6ff8640, 0xffffffffb6f82158, 0x112) went to [0xb6ff8640..0xb6ff86b3) Code can be run in the target. Found function, has local address 0xffffffffb6f84000 and remote address 0xffffffffffffffff Couldn't disassemble function : Couldn't find code range for function _Z12$__lldb_exprPv Sections: [0xb6f84000+0x3c]->0xb6ff9020 (alignment 4, section ID 0, name .text) ... HandleCommand, command did not succeed error: Expression can't be run, because there is no JIT compiled function Expected: IRMemoryMap::WriteMemory (0xb6ff8640, 0xb6faa15c, 0x128) went to [0xb6ff8640..0xb6ff86c3) IRExecutionUnit::GetRemoteAddressForLocal() found 0xb6fac000 in [0xb6fac000..0xb6fac040], and returned 0xb6ff9020 from [0xb6ff9020..0xb6ff9060]. Code can be run in the target. Found function, has local address 0xb6fac000 and remote address 0xb6ff9020 Function's code range is [0xb6ff9020+0x40] ... Function data has contents: 0xb6ff9020: 10 4c 2d e9 08 b0 8d e2 08 d0 4d e2 00 40 a0 e1 ... Function disassembly: 0xb6ff9020: 0xe92d4c10 push {r4, r10, r11, lr} Differential revision: https://reviews.llvm.org/D71498
2019-12-21 18:12:17 +08:00
"IRMemoryMap::%s process_sp=0x%" PRIxPTR
", process_sp->CanJIT()=%s, process_sp->IsAlive()=%s",
[lldb] Fix ARM32 inferior calls echo -e '#include <unistd.h>\nint main(void){\nsync();return 0;}'|./bin/clang -g -x c -;./bin/lldb -o 'file ./a.out' -o 'b main' -o r -o 'p (void)sync()' Actual: error: Expression can't be run, because there is no JIT compiled function Expected: <nothing, sync() has been executed> This patch has been checked by: D71707: clang-tidy: new bugprone-pointer-cast-widening https://reviews.llvm.org/D71707 Casting from 32-bit `void *` to `uint64_t` requires an intermediate `uintptr_t` cast otherwise the pointer gets sign-extended: echo -e '#include <stdio.h>\n#include <stdint.h>\nint main(void){void *p=(void *)0x80000000;unsigned long long ull=(unsigned long long)p;unsigned long long ull2=(unsigned long long)(uintptr_t)p;printf("p=%p ull=0x%llx ull2=0x%llx\\n",p,ull,ull2);return 0;}'|gcc -Wall -m32 -x c -;./a.out <stdin>: In function ‘main’: <stdin>:3:66: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] p=0x80000000 ull=0xffffffff80000000 ull2=0x80000000 With debug output: Actual: IRMemoryMap::WriteMemory (0xb6ff8640, 0xffffffffb6f82158, 0x112) went to [0xb6ff8640..0xb6ff86b3) Code can be run in the target. Found function, has local address 0xffffffffb6f84000 and remote address 0xffffffffffffffff Couldn't disassemble function : Couldn't find code range for function _Z12$__lldb_exprPv Sections: [0xb6f84000+0x3c]->0xb6ff9020 (alignment 4, section ID 0, name .text) ... HandleCommand, command did not succeed error: Expression can't be run, because there is no JIT compiled function Expected: IRMemoryMap::WriteMemory (0xb6ff8640, 0xb6faa15c, 0x128) went to [0xb6ff8640..0xb6ff86c3) IRExecutionUnit::GetRemoteAddressForLocal() found 0xb6fac000 in [0xb6fac000..0xb6fac040], and returned 0xb6ff9020 from [0xb6ff9020..0xb6ff9060]. Code can be run in the target. Found function, has local address 0xb6fac000 and remote address 0xb6ff9020 Function's code range is [0xb6ff9020+0x40] ... Function data has contents: 0xb6ff9020: 10 4c 2d e9 08 b0 8d e2 08 d0 4d e2 00 40 a0 e1 ... Function disassembly: 0xb6ff9020: 0xe92d4c10 push {r4, r10, r11, lr} Differential revision: https://reviews.llvm.org/D71498
2019-12-21 18:12:17 +08:00
__FUNCTION__, reinterpret_cast<uintptr_t>(process_sp.get()),
process_sp && process_sp->CanJIT() ? "true" : "false",
process_sp && process_sp->IsAlive() ? "true" : "false");
if (process_sp && process_sp->CanJIT() && process_sp->IsAlive()) {
if (!zero_memory)
allocation_address =
process_sp->AllocateMemory(allocation_size, permissions, error);
else
allocation_address =
process_sp->CallocateMemory(allocation_size, permissions, error);
if (!error.Success())
return LLDB_INVALID_ADDRESS;
} else {
LLDB_LOGF(log,
"IRMemoryMap::%s switching to eAllocationPolicyHostOnly "
"due to failed condition (see previous expr log message)",
__FUNCTION__);
policy = 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 eAllocationPolicyProcessOnly:
process_sp = m_process_wp.lock();
if (process_sp) {
if (process_sp->CanJIT() && process_sp->IsAlive()) {
if (!zero_memory)
allocation_address =
process_sp->AllocateMemory(allocation_size, permissions, error);
else
allocation_address =
process_sp->CallocateMemory(allocation_size, permissions, error);
if (!error.Success())
return LLDB_INVALID_ADDRESS;
} else {
error.SetErrorToGenericError();
error.SetErrorString(
"Couldn't malloc: process doesn't support allocating memory");
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);
m_allocations.emplace(
std::piecewise_construct, std::forward_as_tuple(aligned_address),
std::forward_as_tuple(allocation_address, aligned_address,
allocation_size, permissions, alignment, policy));
if (zero_memory) {
Status write_error;
std::vector<uint8_t> zero_buf(size, 0);
WriteMemory(aligned_address, zero_buf.data(), size, write_error);
}
if (log) {
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;
}
LLDB_LOGF(log,
"IRMemoryMap::Malloc (%" PRIu64 ", 0x%" PRIx64 ", 0x%" PRIx64
", %s) -> 0x%" PRIx64,
(uint64_t)allocation_size, (uint64_t)alignment,
(uint64_t)permissions, policy_string, aligned_address);
}
return aligned_address;
}
void IRMemoryMap::Leak(lldb::addr_t process_address, Status &error) {
error.Clear();
AllocationMap::iterator iter = m_allocations.find(process_address);
if (iter == m_allocations.end()) {
error.SetErrorToGenericError();
error.SetErrorString("Couldn't leak: allocation doesn't exist");
return;
}
Allocation &allocation = iter->second;
allocation.m_leak = true;
}
void IRMemoryMap::Free(lldb::addr_t process_address, Status &error) {
error.Clear();
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: {
lldb::ProcessSP process_sp = m_process_wp.lock();
if (process_sp) {
if (process_sp->CanJIT() && process_sp->IsAlive())
process_sp->DeallocateMemory(
allocation.m_process_alloc); // FindSpace allocated this for real
}
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)) {
LLDB_LOGF(log,
"IRMemoryMap::Free (0x%" PRIx64 ") freed [0x%" PRIx64
"..0x%" PRIx64 ")",
(uint64_t)process_address, iter->second.m_process_start,
iter->second.m_process_start + iter->second.m_size);
}
m_allocations.erase(iter);
}
bool IRMemoryMap::GetAllocSize(lldb::addr_t address, size_t &size) {
AllocationMap::iterator iter = FindAllocation(address, size);
if (iter == m_allocations.end())
return false;
Allocation &al = iter->second;
if (address > (al.m_process_start + al.m_size)) {
size = 0;
return false;
}
if (address > al.m_process_start) {
int dif = address - al.m_process_start;
size = al.m_size - dif;
return true;
}
size = al.m_size;
return true;
}
void IRMemoryMap::WriteMemory(lldb::addr_t process_address,
const uint8_t *bytes, size_t size,
Status &error) {
error.Clear();
AllocationMap::iterator iter = FindAllocation(process_address, size);
if (iter == m_allocations.end()) {
lldb::ProcessSP process_sp = m_process_wp.lock();
if (process_sp) {
process_sp->WriteMemory(process_address, bytes, size, error);
return;
}
error.SetErrorToGenericError();
error.SetErrorString("Couldn't write: no allocation contains the target "
"range and the process doesn't exist");
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.GetByteSize()) {
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.GetByteSize()) {
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)) {
LLDB_LOGF(log,
[lldb] Fix ARM32 inferior calls echo -e '#include <unistd.h>\nint main(void){\nsync();return 0;}'|./bin/clang -g -x c -;./bin/lldb -o 'file ./a.out' -o 'b main' -o r -o 'p (void)sync()' Actual: error: Expression can't be run, because there is no JIT compiled function Expected: <nothing, sync() has been executed> This patch has been checked by: D71707: clang-tidy: new bugprone-pointer-cast-widening https://reviews.llvm.org/D71707 Casting from 32-bit `void *` to `uint64_t` requires an intermediate `uintptr_t` cast otherwise the pointer gets sign-extended: echo -e '#include <stdio.h>\n#include <stdint.h>\nint main(void){void *p=(void *)0x80000000;unsigned long long ull=(unsigned long long)p;unsigned long long ull2=(unsigned long long)(uintptr_t)p;printf("p=%p ull=0x%llx ull2=0x%llx\\n",p,ull,ull2);return 0;}'|gcc -Wall -m32 -x c -;./a.out <stdin>: In function ‘main’: <stdin>:3:66: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] p=0x80000000 ull=0xffffffff80000000 ull2=0x80000000 With debug output: Actual: IRMemoryMap::WriteMemory (0xb6ff8640, 0xffffffffb6f82158, 0x112) went to [0xb6ff8640..0xb6ff86b3) Code can be run in the target. Found function, has local address 0xffffffffb6f84000 and remote address 0xffffffffffffffff Couldn't disassemble function : Couldn't find code range for function _Z12$__lldb_exprPv Sections: [0xb6f84000+0x3c]->0xb6ff9020 (alignment 4, section ID 0, name .text) ... HandleCommand, command did not succeed error: Expression can't be run, because there is no JIT compiled function Expected: IRMemoryMap::WriteMemory (0xb6ff8640, 0xb6faa15c, 0x128) went to [0xb6ff8640..0xb6ff86c3) IRExecutionUnit::GetRemoteAddressForLocal() found 0xb6fac000 in [0xb6fac000..0xb6fac040], and returned 0xb6ff9020 from [0xb6ff9020..0xb6ff9060]. Code can be run in the target. Found function, has local address 0xb6fac000 and remote address 0xb6ff9020 Function's code range is [0xb6ff9020+0x40] ... Function data has contents: 0xb6ff9020: 10 4c 2d e9 08 b0 8d e2 08 d0 4d e2 00 40 a0 e1 ... Function disassembly: 0xb6ff9020: 0xe92d4c10 push {r4, r10, r11, lr} Differential revision: https://reviews.llvm.org/D71498
2019-12-21 18:12:17 +08:00
"IRMemoryMap::WriteMemory (0x%" PRIx64 ", 0x%" PRIxPTR
", 0x%" PRId64 ") went to [0x%" PRIx64 "..0x%" PRIx64 ")",
[lldb] Fix ARM32 inferior calls echo -e '#include <unistd.h>\nint main(void){\nsync();return 0;}'|./bin/clang -g -x c -;./bin/lldb -o 'file ./a.out' -o 'b main' -o r -o 'p (void)sync()' Actual: error: Expression can't be run, because there is no JIT compiled function Expected: <nothing, sync() has been executed> This patch has been checked by: D71707: clang-tidy: new bugprone-pointer-cast-widening https://reviews.llvm.org/D71707 Casting from 32-bit `void *` to `uint64_t` requires an intermediate `uintptr_t` cast otherwise the pointer gets sign-extended: echo -e '#include <stdio.h>\n#include <stdint.h>\nint main(void){void *p=(void *)0x80000000;unsigned long long ull=(unsigned long long)p;unsigned long long ull2=(unsigned long long)(uintptr_t)p;printf("p=%p ull=0x%llx ull2=0x%llx\\n",p,ull,ull2);return 0;}'|gcc -Wall -m32 -x c -;./a.out <stdin>: In function ‘main’: <stdin>:3:66: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] p=0x80000000 ull=0xffffffff80000000 ull2=0x80000000 With debug output: Actual: IRMemoryMap::WriteMemory (0xb6ff8640, 0xffffffffb6f82158, 0x112) went to [0xb6ff8640..0xb6ff86b3) Code can be run in the target. Found function, has local address 0xffffffffb6f84000 and remote address 0xffffffffffffffff Couldn't disassemble function : Couldn't find code range for function _Z12$__lldb_exprPv Sections: [0xb6f84000+0x3c]->0xb6ff9020 (alignment 4, section ID 0, name .text) ... HandleCommand, command did not succeed error: Expression can't be run, because there is no JIT compiled function Expected: IRMemoryMap::WriteMemory (0xb6ff8640, 0xb6faa15c, 0x128) went to [0xb6ff8640..0xb6ff86c3) IRExecutionUnit::GetRemoteAddressForLocal() found 0xb6fac000 in [0xb6fac000..0xb6fac040], and returned 0xb6ff9020 from [0xb6ff9020..0xb6ff9060]. Code can be run in the target. Found function, has local address 0xb6fac000 and remote address 0xb6ff9020 Function's code range is [0xb6ff9020+0x40] ... Function data has contents: 0xb6ff9020: 10 4c 2d e9 08 b0 8d e2 08 d0 4d e2 00 40 a0 e1 ... Function disassembly: 0xb6ff9020: 0xe92d4c10 push {r4, r10, r11, lr} Differential revision: https://reviews.llvm.org/D71498
2019-12-21 18:12:17 +08:00
(uint64_t)process_address, reinterpret_cast<uintptr_t>(bytes), (uint64_t)size,
(uint64_t)allocation.m_process_start,
(uint64_t)allocation.m_process_start +
(uint64_t)allocation.m_size);
}
}
void IRMemoryMap::WriteScalarToMemory(lldb::addr_t process_address,
Scalar &scalar, size_t size,
Status &error) {
error.Clear();
if (size == UINT32_MAX)
size = scalar.GetByteSize();
if (size > 0) {
uint8_t buf[32];
const size_t mem_size =
scalar.GetAsMemoryData(buf, size, GetByteOrder(), error);
if (mem_size > 0) {
return WriteMemory(process_address, buf, mem_size, error);
} else {
error.SetErrorToGenericError();
error.SetErrorString(
"Couldn't write scalar: failed to get scalar as memory data");
}
} else {
error.SetErrorToGenericError();
error.SetErrorString("Couldn't write scalar: its size was zero");
}
return;
}
void IRMemoryMap::WritePointerToMemory(lldb::addr_t process_address,
lldb::addr_t address, Status &error) {
error.Clear();
Scalar scalar(address);
WriteScalarToMemory(process_address, scalar, GetAddressByteSize(), error);
}
void IRMemoryMap::ReadMemory(uint8_t *bytes, lldb::addr_t process_address,
size_t size, Status &error) {
error.Clear();
AllocationMap::iterator iter = FindAllocation(process_address, size);
if (iter == m_allocations.end()) {
lldb::ProcessSP process_sp = m_process_wp.lock();
if (process_sp) {
process_sp->ReadMemory(process_address, bytes, size, error);
return;
}
lldb::TargetSP target_sp = m_target_wp.lock();
if (target_sp) {
Address absolute_address(process_address);
target_sp->ReadMemory(absolute_address, false, bytes, size, error);
return;
}
error.SetErrorToGenericError();
error.SetErrorString("Couldn't read: no allocation contains the target "
"range, and neither the process nor the target exist");
return;
}
Allocation &allocation = iter->second;
uint64_t offset = process_address - allocation.m_process_start;
if (offset > allocation.m_size) {
error.SetErrorToGenericError();
error.SetErrorString("Couldn't read: data is not in the allocation");
return;
}
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.GetByteSize()) {
error.SetErrorToGenericError();
error.SetErrorString("Couldn't read: data buffer is empty");
return;
}
if (allocation.m_data.GetByteSize() < offset + size) {
error.SetErrorToGenericError();
error.SetErrorString("Couldn't read: not enough underlying data");
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.GetByteSize()) {
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)) {
LLDB_LOGF(log,
[lldb] Fix ARM32 inferior calls echo -e '#include <unistd.h>\nint main(void){\nsync();return 0;}'|./bin/clang -g -x c -;./bin/lldb -o 'file ./a.out' -o 'b main' -o r -o 'p (void)sync()' Actual: error: Expression can't be run, because there is no JIT compiled function Expected: <nothing, sync() has been executed> This patch has been checked by: D71707: clang-tidy: new bugprone-pointer-cast-widening https://reviews.llvm.org/D71707 Casting from 32-bit `void *` to `uint64_t` requires an intermediate `uintptr_t` cast otherwise the pointer gets sign-extended: echo -e '#include <stdio.h>\n#include <stdint.h>\nint main(void){void *p=(void *)0x80000000;unsigned long long ull=(unsigned long long)p;unsigned long long ull2=(unsigned long long)(uintptr_t)p;printf("p=%p ull=0x%llx ull2=0x%llx\\n",p,ull,ull2);return 0;}'|gcc -Wall -m32 -x c -;./a.out <stdin>: In function ‘main’: <stdin>:3:66: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] p=0x80000000 ull=0xffffffff80000000 ull2=0x80000000 With debug output: Actual: IRMemoryMap::WriteMemory (0xb6ff8640, 0xffffffffb6f82158, 0x112) went to [0xb6ff8640..0xb6ff86b3) Code can be run in the target. Found function, has local address 0xffffffffb6f84000 and remote address 0xffffffffffffffff Couldn't disassemble function : Couldn't find code range for function _Z12$__lldb_exprPv Sections: [0xb6f84000+0x3c]->0xb6ff9020 (alignment 4, section ID 0, name .text) ... HandleCommand, command did not succeed error: Expression can't be run, because there is no JIT compiled function Expected: IRMemoryMap::WriteMemory (0xb6ff8640, 0xb6faa15c, 0x128) went to [0xb6ff8640..0xb6ff86c3) IRExecutionUnit::GetRemoteAddressForLocal() found 0xb6fac000 in [0xb6fac000..0xb6fac040], and returned 0xb6ff9020 from [0xb6ff9020..0xb6ff9060]. Code can be run in the target. Found function, has local address 0xb6fac000 and remote address 0xb6ff9020 Function's code range is [0xb6ff9020+0x40] ... Function data has contents: 0xb6ff9020: 10 4c 2d e9 08 b0 8d e2 08 d0 4d e2 00 40 a0 e1 ... Function disassembly: 0xb6ff9020: 0xe92d4c10 push {r4, r10, r11, lr} Differential revision: https://reviews.llvm.org/D71498
2019-12-21 18:12:17 +08:00
"IRMemoryMap::ReadMemory (0x%" PRIx64 ", 0x%" PRIxPTR
", 0x%" PRId64 ") came from [0x%" PRIx64 "..0x%" PRIx64 ")",
[lldb] Fix ARM32 inferior calls echo -e '#include <unistd.h>\nint main(void){\nsync();return 0;}'|./bin/clang -g -x c -;./bin/lldb -o 'file ./a.out' -o 'b main' -o r -o 'p (void)sync()' Actual: error: Expression can't be run, because there is no JIT compiled function Expected: <nothing, sync() has been executed> This patch has been checked by: D71707: clang-tidy: new bugprone-pointer-cast-widening https://reviews.llvm.org/D71707 Casting from 32-bit `void *` to `uint64_t` requires an intermediate `uintptr_t` cast otherwise the pointer gets sign-extended: echo -e '#include <stdio.h>\n#include <stdint.h>\nint main(void){void *p=(void *)0x80000000;unsigned long long ull=(unsigned long long)p;unsigned long long ull2=(unsigned long long)(uintptr_t)p;printf("p=%p ull=0x%llx ull2=0x%llx\\n",p,ull,ull2);return 0;}'|gcc -Wall -m32 -x c -;./a.out <stdin>: In function ‘main’: <stdin>:3:66: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] p=0x80000000 ull=0xffffffff80000000 ull2=0x80000000 With debug output: Actual: IRMemoryMap::WriteMemory (0xb6ff8640, 0xffffffffb6f82158, 0x112) went to [0xb6ff8640..0xb6ff86b3) Code can be run in the target. Found function, has local address 0xffffffffb6f84000 and remote address 0xffffffffffffffff Couldn't disassemble function : Couldn't find code range for function _Z12$__lldb_exprPv Sections: [0xb6f84000+0x3c]->0xb6ff9020 (alignment 4, section ID 0, name .text) ... HandleCommand, command did not succeed error: Expression can't be run, because there is no JIT compiled function Expected: IRMemoryMap::WriteMemory (0xb6ff8640, 0xb6faa15c, 0x128) went to [0xb6ff8640..0xb6ff86c3) IRExecutionUnit::GetRemoteAddressForLocal() found 0xb6fac000 in [0xb6fac000..0xb6fac040], and returned 0xb6ff9020 from [0xb6ff9020..0xb6ff9060]. Code can be run in the target. Found function, has local address 0xb6fac000 and remote address 0xb6ff9020 Function's code range is [0xb6ff9020+0x40] ... Function data has contents: 0xb6ff9020: 10 4c 2d e9 08 b0 8d e2 08 d0 4d e2 00 40 a0 e1 ... Function disassembly: 0xb6ff9020: 0xe92d4c10 push {r4, r10, r11, lr} Differential revision: https://reviews.llvm.org/D71498
2019-12-21 18:12:17 +08:00
(uint64_t)process_address, reinterpret_cast<uintptr_t>(bytes), (uint64_t)size,
(uint64_t)allocation.m_process_start,
(uint64_t)allocation.m_process_start +
(uint64_t)allocation.m_size);
}
}
void IRMemoryMap::ReadScalarFromMemory(Scalar &scalar,
lldb::addr_t process_address,
size_t size, Status &error) {
error.Clear();
if (size > 0) {
DataBufferHeap buf(size, 0);
ReadMemory(buf.GetBytes(), process_address, size, error);
if (!error.Success())
return;
DataExtractor extractor(buf.GetBytes(), buf.GetByteSize(), GetByteOrder(),
GetAddressByteSize());
lldb::offset_t offset = 0;
switch (size) {
default:
error.SetErrorToGenericError();
error.SetErrorStringWithFormat(
"Couldn't read scalar: unsupported size %" PRIu64, (uint64_t)size);
return;
case 1:
scalar = extractor.GetU8(&offset);
break;
case 2:
scalar = extractor.GetU16(&offset);
break;
case 4:
scalar = extractor.GetU32(&offset);
break;
case 8:
scalar = extractor.GetU64(&offset);
break;
}
} else {
error.SetErrorToGenericError();
error.SetErrorString("Couldn't read scalar: its size was zero");
}
return;
}
void IRMemoryMap::ReadPointerFromMemory(lldb::addr_t *address,
lldb::addr_t process_address,
Status &error) {
error.Clear();
Scalar pointer_scalar;
ReadScalarFromMemory(pointer_scalar, process_address, GetAddressByteSize(),
error);
if (!error.Success())
return;
*address = pointer_scalar.ULongLong();
return;
}
void IRMemoryMap::GetMemoryData(DataExtractor &extractor,
lldb::addr_t process_address, size_t size,
Status &error) {
error.Clear();
if (size > 0) {
AllocationMap::iterator iter = FindAllocation(process_address, size);
if (iter == m_allocations.end()) {
error.SetErrorToGenericError();
error.SetErrorStringWithFormat(
"Couldn't find an allocation containing [0x%" PRIx64 "..0x%" PRIx64
")",
process_address, process_address + size);
return;
}
Allocation &allocation = iter->second;
switch (allocation.m_policy) {
default:
error.SetErrorToGenericError();
error.SetErrorString(
"Couldn't get memory data: invalid allocation policy");
return;
case eAllocationPolicyProcessOnly:
error.SetErrorToGenericError();
error.SetErrorString(
"Couldn't get memory data: memory is only in the target");
return;
case eAllocationPolicyMirror: {
lldb::ProcessSP process_sp = m_process_wp.lock();
if (!allocation.m_data.GetByteSize()) {
error.SetErrorToGenericError();
error.SetErrorString("Couldn't get memory data: data buffer is empty");
return;
}
if (process_sp) {
process_sp->ReadMemory(allocation.m_process_start,
allocation.m_data.GetBytes(),
allocation.m_data.GetByteSize(), error);
if (!error.Success())
return;
uint64_t offset = process_address - allocation.m_process_start;
extractor = DataExtractor(allocation.m_data.GetBytes() + offset, size,
GetByteOrder(), GetAddressByteSize());
return;
}
} break;
case eAllocationPolicyHostOnly:
if (!allocation.m_data.GetByteSize()) {
error.SetErrorToGenericError();
error.SetErrorString("Couldn't get memory data: data buffer is empty");
return;
}
uint64_t offset = process_address - allocation.m_process_start;
extractor = DataExtractor(allocation.m_data.GetBytes() + offset, size,
GetByteOrder(), GetAddressByteSize());
return;
}
} else {
error.SetErrorToGenericError();
error.SetErrorString("Couldn't get memory data: its size was zero");
return;
}
}