Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/Makefile =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/Makefile +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +C_SOURCES := main.c + +include $(LEVEL)/Makefile.rules Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/TestWatchpointSizes.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/TestWatchpointSizes.py +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/TestWatchpointSizes.py @@ -0,0 +1,117 @@ +""" +Test watchpoint size cases (1-byte, 2-byte, 4-byte). +Make sure we can watch all bytes, words or double words individually +when they are packed in a 8-byte region. + +""" + +from __future__ import print_function + +import os, time +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class WatchpointSizeTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + mydir = TestBase.compute_mydir(__file__) + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + + # Source filename. + self.source = 'main.c' + + # Output filename. + self.exe_name = 'a.out' + self.d = {'C_SOURCES': self.source, 'EXE': self.exe_name} + + @expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported + @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") + @expectedFailureAll(archs=['s390x']) # Read-write watchpoints not supported on SystemZ + def test_byte_size_watchpoints_with_byte_selection(self): + """Test to selectively watch different bytes in a 8-byte array.""" + self.run_watchpoint_size_test('byteArray', 8, '1') + + @expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported + @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") + @expectedFailureAll(archs=['s390x']) # Read-write watchpoints not supported on SystemZ + def test_two_byte_watchpoints_with_word_selection(self): + """Test to selectively watch different words in an 8-byte word array.""" + self.run_watchpoint_size_test('wordArray', 4, '2') + + @expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported + @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") + @expectedFailureAll(archs=['s390x']) # Read-write watchpoints not supported on SystemZ + def test_four_byte_watchpoints_with_dword_selection(self): + """Test to selectively watch two double words in an 8-byte dword array.""" + self.run_watchpoint_size_test('dwordArray', 2, '4') + + def run_watchpoint_size_test(self, arrayName, array_size, watchsize): + self.build(dictionary=self.d) + self.setTearDownCleanup(dictionary=self.d) + + exe = os.path.join(os.getcwd(), self.exe_name) + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + # Detect line number after which we are going to increment arrayName. + loc_line = line_number('main.c', '// About to write ' + arrayName) + + # Set a breakpoint on the line detected above. + lldbutil.run_break_set_by_file_and_line (self, "main.c",loc_line, + num_expected_locations=1, loc_exact=True) + + # Run the program. + self.runCmd("run", RUN_SUCCEEDED) + + for i in range(array_size): + # We should be stopped again due to the breakpoint. + # The stop reason of the thread should be breakpoint. + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs = ['stopped', 'stop reason = breakpoint']) + + # Set a read_write type watchpoint arrayName + watch_loc=arrayName+"[" + str(i) + "]" + self.expect("watchpoint set variable -w read_write " + watch_loc, + WATCHPOINT_CREATED, + substrs = ['Watchpoint created', 'size = ' + watchsize, 'type = rw']) + + # Use the '-v' option to do verbose listing of the watchpoint. + # The hit count should be 0 initially. + self.expect("watchpoint list -v", substrs = ['hit_count = 0']) + + self.runCmd("process continue") + + # We should be stopped due to the watchpoint. + # The stop reason of the thread should be watchpoint. + self.expect("thread list", STOPPED_DUE_TO_WATCHPOINT, + substrs = ['stopped', 'stop reason = watchpoint']) + + # Use the '-v' option to do verbose listing of the watchpoint. + # The hit count should now be 1. + self.expect("watchpoint list -v", + substrs = ['hit_count = 1']) + + self.runCmd("process continue") + + # We should be stopped due to the watchpoint. + # The stop reason of the thread should be watchpoint. + self.expect("thread list", STOPPED_DUE_TO_WATCHPOINT, + substrs = ['stopped', 'stop reason = watchpoint']) + + # Use the '-v' option to do verbose listing of the watchpoint. + # The hit count should now be 1. + # Verify hit_count has been updated after value has been read. + self.expect("watchpoint list -v", + substrs = ['hit_count = 2']) + + # Delete the watchpoint immediately, but set auto-confirm to true first. + self.runCmd("settings set auto-confirm true") + self.expect("watchpoint delete", substrs = ['All watchpoints removed.']) + # Restore the original setting of auto-confirm. + self.runCmd("settings clear auto-confirm") + + self.runCmd("process continue") Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/main.c =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/main.c +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/main.c @@ -0,0 +1,66 @@ +//===-- main.c --------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include +#include + +uint64_t pad0 = 0; +uint8_t byteArray[8] = {0}; +uint64_t pad1 = 0; +uint16_t wordArray[4] = {0}; +uint64_t pad2 = 0; +uint32_t dwordArray[2] = {0}; + +int main(int argc, char** argv) { + + int i; + uint8_t localByte; + uint16_t localWord; + uint32_t localDword; + + for (i = 0; i < 8; i++) + { + printf("About to write byteArray[%d] ...\n", i); // About to write byteArray + pad0++; + byteArray[i]++; + pad1++; + localByte = byteArray[i]; // Here onwards we should'nt be stopped in loop + byteArray[i]++; + localByte = byteArray[i]; + } + + pad0 = 0; + pad1 = 0; + + for (i = 0; i < 4; i++) + { + printf("About to write wordArray[%d] ...\n", i); // About to write wordArray + pad0++; + wordArray[i]++; + pad1++; + localWord = wordArray[i]; // Here onwards we should'nt be stopped in loop + wordArray[i]++; + localWord = wordArray[i]; + } + + pad0 = 0; + pad1 = 0; + + for (i = 0; i < 2; i++) + { + printf("About to write dwordArray[%d] ...\n", i); // About to write dwordArray + pad0++; + dwordArray[i]++; + pad1++; + localDword = dwordArray[i]; // Here onwards we shouldn't be stopped in loop + dwordArray[i]++; + localDword = dwordArray[i]; + } + + return 0; +} Index: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h +++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h @@ -74,6 +74,9 @@ GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) override; lldb::addr_t + GetWatchpointHitAddress (uint32_t wp_index) override; + + lldb::addr_t GetWatchpointAddress (uint32_t wp_index) override; uint32_t @@ -161,6 +164,8 @@ struct DREG { lldb::addr_t address; // Breakpoint/watchpoint address value. + lldb::addr_t hit_addr; // Address at which last watchpoint trigger exception occurred. + lldb::addr_t real_addr; // Address value that should cause target to stop. uint32_t control; // Breakpoint/watchpoint control value. uint32_t refcount; // Serves as enable/disable and refernce counter. }; Index: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -566,6 +566,7 @@ return LLDB_INVALID_INDEX32; uint32_t control_value = 0, wp_index = 0; + lldb::addr_t real_addr = addr; // Check if we are setting watchpoint other than read/write/access // Also update watchpoint flag to match AArch64 write-read bit configuration. @@ -588,9 +589,23 @@ return LLDB_INVALID_INDEX32; // Check 8-byte alignment for hardware watchpoint target address. - // TODO: Add support for watching un-aligned addresses + // Below is a hack to recalculate address and size in order to + // make sure we can watch non 8-byte alligned addresses as well. if (addr & 0x07) - return LLDB_INVALID_INDEX32; + { + uint8_t watch_mask = (addr & 0x07) + size; + + if (watch_mask > 0x08) + return LLDB_INVALID_INDEX32; + else if (watch_mask <= 0x02) + size = 2; + else if (watch_mask <= 0x04) + size = 4; + else + size = 8; + + addr = addr & (~0x07); + } // Setup control value control_value = watch_flags << 3; @@ -620,6 +635,7 @@ if ((m_hwp_regs[wp_index].control & 1) == 0) { // Update watchpoint in local cache + m_hwp_regs[wp_index].real_addr = real_addr; m_hwp_regs[wp_index].address = addr; m_hwp_regs[wp_index].control = control_value; m_hwp_regs[wp_index].refcount = 1; @@ -801,6 +817,7 @@ if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size) { + m_hwp_regs[wp_index].hit_addr = trap_addr; return Error(); } } @@ -821,7 +838,24 @@ return LLDB_INVALID_ADDRESS; if (WatchpointIsEnabled(wp_index)) - return m_hwp_regs[wp_index].address; + return m_hwp_regs[wp_index].real_addr; + else + return LLDB_INVALID_ADDRESS; +} + +lldb::addr_t +NativeRegisterContextLinux_arm64::GetWatchpointHitAddress (uint32_t wp_index) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); + + if (log) + log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].hit_addr; else return LLDB_INVALID_ADDRESS; } Index: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -2059,7 +2059,8 @@ { WatchpointSP wp_sp; ArchSpec::Core core = GetTarget().GetArchitecture().GetCore(); - if (core >= ArchSpec::kCore_mips_first && core <= ArchSpec::kCore_mips_last) + if ((core >= ArchSpec::kCore_mips_first && core <= ArchSpec::kCore_mips_last) || + (core >= ArchSpec::eCore_arm_arm64 && core <= ArchSpec::eCore_arm_aarch64)) wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_hit_addr); if (!wp_sp) wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr);