diff --git a/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h --- a/lldb/include/lldb/Target/ABI.h +++ b/lldb/include/lldb/Target/ABI.h @@ -147,6 +147,8 @@ virtual bool GetPointerReturnRegister(const char *&name) { return false; } + virtual uint64_t GetStackFrameSize() { return 512 * 1024; } + static lldb::ABISP FindPlugin(lldb::ProcessSP process_sp, const ArchSpec &arch); protected: diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -204,6 +204,12 @@ uint64_t GetExprErrorLimit() const; + uint64_t GetExprAllocAddress() const; + + uint64_t GetExprAllocSize() const; + + uint64_t GetExprAllocAlign() const; + bool GetUseHexImmediates() const; bool GetUseFastStepping() const; diff --git a/lldb/source/Expression/IRMemoryMap.cpp b/lldb/source/Expression/IRMemoryMap.cpp --- a/lldb/source/Expression/IRMemoryMap.cpp +++ b/lldb/source/Expression/IRMemoryMap.cpp @@ -92,26 +92,26 @@ ret = llvm::alignTo(addr + alloc_size, 4096); } + uint64_t end_of_memory; + switch (GetAddressByteSize()) { + case 2: + end_of_memory = 0xffffull; + break; + case 4: + end_of_memory = 0xffffffffull; + break; + case 8: + end_of_memory = 0xffffffffffffffffull; + break; + default: + lldbassert(false && "Invalid address size."); + return LLDB_INVALID_ADDRESS; + } + // 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) { - uint64_t end_of_memory; - switch (process_sp->GetAddressByteSize()) { - case 2: - end_of_memory = 0xffffull; - break; - case 4: - end_of_memory = 0xffffffffull; - break; - case 8: - end_of_memory = 0xffffffffffffffffull; - break; - default: - lldbassert(false && "Invalid address size."); - return LLDB_INVALID_ADDRESS; - } - MemoryRegionInfo region_info; Status err = process_sp->GetMemoryRegionInfo(ret, region_info); if (err.Success()) { @@ -147,29 +147,40 @@ // 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 2: - ret = 0x8000ull; - break; - case 4: - ret = 0xee000000ull; - break; - case 8: - ret = 0xdead0fff00000000ull; - break; - default: - lldbassert(false && "Invalid address size."); + uint64_t alloc_address = target_sp->GetExprAllocAddress(); + if (alloc_address > 0) { + if (alloc_address >= end_of_memory) { + lldbassert(0 && "The allocation address for expression evaluation must " + "be within process address space"); return LLDB_INVALID_ADDRESS; } + ret = alloc_address; + } else { + uint32_t address_byte_size = GetAddressByteSize(); + if (address_byte_size != UINT32_MAX) { + switch (address_byte_size) { + case 2: + ret = 0x8000ull; + break; + case 4: + ret = 0xee000000ull; + break; + case 8: + ret = 0xdead0fff00000000ull; + break; + default: + lldbassert(false && "Invalid address size."); + return LLDB_INVALID_ADDRESS; + } + } } } else { auto back = m_allocations.rbegin(); lldb::addr_t addr = back->first; size_t alloc_size = back->second.m_size; - auto arch = target_sp->GetArchitecture().GetTriple().getArch(); - auto align = arch == llvm::Triple::msp430 ? 512 : 4096; + uint64_t align = target_sp->GetExprAllocAlign(); + if (align == 0) + align = 4096; ret = llvm::alignTo(addr + alloc_size, align); } diff --git a/lldb/source/Expression/LLVMUserExpression.cpp b/lldb/source/Expression/LLVMUserExpression.cpp --- a/lldb/source/Expression/LLVMUserExpression.cpp +++ b/lldb/source/Expression/LLVMUserExpression.cpp @@ -23,6 +23,7 @@ #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ABI.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/StackFrame.h" @@ -34,6 +35,7 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" +using namespace lldb; using namespace lldb_private; char LLVMUserExpression::ID; @@ -333,9 +335,14 @@ if (m_can_interpret && m_stack_frame_bottom == LLDB_INVALID_ADDRESS) { Status alloc_error; - auto arch = target->GetArchitecture().GetTriple().getArch(); - const size_t stack_frame_size = - arch == llvm::Triple::msp430 ? 512 : 512 * 1024; + size_t stack_frame_size = target->GetExprAllocSize(); + if (stack_frame_size == 0) { + ABISP abi_sp; + if (process && (abi_sp = process->GetABI())) + stack_frame_size = abi_sp->GetStackFrameSize(); + else + stack_frame_size = 512 * 1024; + } const bool zero_memory = false; diff --git a/lldb/source/Plugins/ABI/MSP430/ABISysV_msp430.h b/lldb/source/Plugins/ABI/MSP430/ABISysV_msp430.h --- a/lldb/source/Plugins/ABI/MSP430/ABISysV_msp430.h +++ b/lldb/source/Plugins/ABI/MSP430/ABISysV_msp430.h @@ -55,6 +55,8 @@ const lldb_private::RegisterInfo * GetRegisterInfoArray(uint32_t &count) override; + uint64_t GetStackFrameSize() override { return 512; } + //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -4586,6 +4586,24 @@ g_target_properties[idx].default_uint_value); } +uint64_t TargetProperties::GetExprAllocAddress() const { + const uint32_t idx = ePropertyExprAllocAddress; + return m_collection_sp->GetPropertyAtIndexAsUInt64( + nullptr, idx, g_target_properties[idx].default_uint_value); +} + +uint64_t TargetProperties::GetExprAllocSize() const { + const uint32_t idx = ePropertyExprAllocSize; + return m_collection_sp->GetPropertyAtIndexAsUInt64( + nullptr, idx, g_target_properties[idx].default_uint_value); +} + +uint64_t TargetProperties::GetExprAllocAlign() const { + const uint32_t idx = ePropertyExprAllocAlign; + return m_collection_sp->GetPropertyAtIndexAsUInt64( + nullptr, idx, g_target_properties[idx].default_uint_value); +} + bool TargetProperties::GetBreakpointsConsultPlatformAvoidList() { const uint32_t idx = ePropertyBreakpointUseAvoidList; return m_collection_sp->GetPropertyAtIndexAsBoolean(idx).value_or( diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -24,6 +24,15 @@ DefaultUnsignedValue<5>, Desc<"The maximum amount of errors to emit while parsing an expression. " "A value of 0 means to always continue parsing if possible.">; + def ExprAllocAddress: Property<"expr-alloc-address", "UInt64">, + DefaultUnsignedValue<0>, + Desc<"Start address within the process address space of memory allocation for expression evaluation.">; + def ExprAllocSize: Property<"expr-alloc-size", "UInt64">, + DefaultUnsignedValue<0>, + Desc<"Amount of memory in bytes to allocate for expression evaluation.">; + def ExprAllocAlign: Property<"expr-alloc-align", "UInt64">, + DefaultUnsignedValue<0>, + Desc<"Alignment for each memory allocation for expression evaluation.">; def PreferDynamic: Property<"prefer-dynamic-value", "Enum">, DefaultEnumValue<"eDynamicDontRunTarget">, EnumValues<"OptionEnumValues(g_dynamic_value_types)">, diff --git a/lldb/test/API/commands/expression/memory-allocation/Makefile b/lldb/test/API/commands/expression/memory-allocation/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/commands/expression/memory-allocation/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/commands/expression/memory-allocation/TestMemoryAllocSettings.py b/lldb/test/API/commands/expression/memory-allocation/TestMemoryAllocSettings.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/commands/expression/memory-allocation/TestMemoryAllocSettings.py @@ -0,0 +1,35 @@ +""" +Test changing setting for expression memory allocation. +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestMemoryAllocSettings(TestBase): + + def test(self): + """Test changing settings for expression memory allocation.""" + self.build() + target = self.createTestTarget() + + self.log_file = self.getBuildArtifact("log-expr.txt") + + self.runCmd("settings set target.expr-alloc-address 0xdead0000") + self.runCmd("settings set target.expr-alloc-size 10000") + self.runCmd("settings set target.expr-alloc-align 0x1000") + + self.runCmd("log enable lldb expr -f " + self.log_file) + self.runCmd("expression -- int foo; &foo") + + self.assertTrue(os.path.isfile(self.log_file)) + with open(self.log_file, 'r') as f: + log = f.read() + + alloc0 = re.search('^.*IRMemoryMap::Malloc.+?0xdead0000.*$', log, re.MULTILINE) + # Malloc adds additional bytes to allocation size, hence 10007 + alloc1 = re.search('^.*IRMemoryMap::Malloc\s*?\(10007.+?0xdead1000.*$', log, re.MULTILINE) + self.assertTrue(alloc0, "Couldn't find an allocation at a given address.") + self.assertTrue(alloc1, "Couldn't find an allocation of a given size at a given address.") + diff --git a/lldb/test/API/commands/expression/memory-allocation/main.cpp b/lldb/test/API/commands/expression/memory-allocation/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/commands/expression/memory-allocation/main.cpp @@ -0,0 +1,3 @@ +int main() { + return 0; +}