Index: packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/TestWatchpointSizes.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/TestWatchpointSizes.py +++ packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/TestWatchpointSizes.py @@ -40,7 +40,10 @@ @expectedFailureAll(archs=['s390x']) 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') + if self.getArchitecture() in ['arm']: + self.run_watchpoint_size_test('byteArray', 8, '1', 1) + else: + self.run_watchpoint_size_test('byteArray', 8, '1', 0) # Watchpoints not supported @expectedFailureAndroid(archs=['arm', 'aarch64']) @@ -51,7 +54,10 @@ @expectedFailureAll(archs=['s390x']) 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') + if self.getArchitecture() in ['arm']: + self.run_watchpoint_size_test('wordArray', 4, '2', 1) + else: + self.run_watchpoint_size_test('wordArray', 4, '2', 0) # Watchpoints not supported @expectedFailureAndroid(archs=['arm', 'aarch64']) @@ -62,9 +68,12 @@ @expectedFailureAll(archs=['s390x']) 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') + if self.getArchitecture() in ['arm']: + self.run_watchpoint_size_test('dwordArray', 2, '4', 1) + else: + self.run_watchpoint_size_test('dwordArray', 2, '4', 0) - def run_watchpoint_size_test(self, arrayName, array_size, watchsize): + def run_watchpoint_size_test(self, arrayName, array_size, watchsize, slots): self.build(dictionary=self.d) self.setTearDownCleanup(dictionary=self.d) @@ -101,7 +110,9 @@ # 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.expect("watchpoint list -v " + str(i+1), + substrs=['watchpoint spec = \'' + arrayName + + '[' + str(i) + ']\'', 'hit_count = 0']) self.runCmd("process continue") @@ -112,8 +123,9 @@ # 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.expect("watchpoint list -v " + str(i+1), + substrs=['watchpoint spec = \'' + arrayName + + '[' + str(i) + ']\'', 'hit_count = 1']) self.runCmd("process continue") @@ -125,16 +137,21 @@ # 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", + self.expect("watchpoint list -v " + str(i+1), + substrs=['watchpoint spec = \'' + arrayName + + '[' + str(i) + ']\'', 'hit_count = 2']) + + # Delete watchpoint if multiple watchpoint slots are not enabled. + if slots == 0: + # Set auto-confirm to true + 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") + # Restore the original setting of auto-confirm. + self.runCmd("settings clear auto-confirm") + + # Continue after hitting watchpoint twice (Read/Write) + if slots != 0: + self.runCmd("process continue") self.runCmd("process continue") Index: packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/main.c =================================================================== --- packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/main.c +++ packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/main.c @@ -30,7 +30,7 @@ byteArray[i] = 7; pad1++; localByte = byteArray[i]; // Here onwards we should'nt be stopped in loop - byteArray[i]++; + localByte = byteArray[i]; } @@ -44,7 +44,7 @@ wordArray[i] = 7; pad1++; localWord = wordArray[i]; // Here onwards we should'nt be stopped in loop - wordArray[i]++; + localWord = wordArray[i]; } @@ -58,7 +58,7 @@ dwordArray[i] = 7; pad1++; localDword = dwordArray[i]; // Here onwards we shouldn't be stopped in loop - dwordArray[i]++; + localDword = dwordArray[i]; } Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp @@ -410,7 +410,6 @@ if ((m_hbr_regs[bp_index].control & 1) == 0) { m_hbr_regs[bp_index].address = addr; m_hbr_regs[bp_index].control = control_value; - m_hbr_regs[bp_index].refcount = 1; // PTRACE call to set corresponding hardware breakpoint register. error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index); @@ -418,7 +417,6 @@ if (error.Fail()) { m_hbr_regs[bp_index].address = 0; m_hbr_regs[bp_index].control &= ~1; - m_hbr_regs[bp_index].refcount = 0; return LLDB_INVALID_INDEX32; } @@ -508,8 +506,19 @@ if (error.Fail()) return LLDB_INVALID_INDEX32; - uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0; + uint32_t control_value = 0; lldb::addr_t real_addr = addr; + uint32_t wp_index = LLDB_INVALID_INDEX32; + + // Find out how many bytes we need to watch after 4-byte alignment boundary. + uint8_t watch_mask = (addr & 0x03) + size; + + // We cannot watch zero or more than 4 bytes after 4-byte alignment boundary. + if (size == 0 || watch_mask > 4) + return LLDB_INVALID_INDEX32; + + // Strip away last two bits of address for byte/half-word/word selection. + addr &= ~((lldb::addr_t)3); // Check if we are setting watchpoint other than read/write/access // Also update watchpoint flag to match Arm write-read bit configuration. @@ -526,40 +535,46 @@ return LLDB_INVALID_INDEX32; } - // Can't watch zero bytes - // Can't watch more than 4 bytes per WVR/WCR pair - - if (size == 0 || size > 4) - return LLDB_INVALID_INDEX32; - - // Check 4-byte alignment for hardware watchpoint target address. - // Below is a hack to recalculate address and size in order to - // make sure we can watch non 4-byte alligned addresses as well. - if (addr & 0x03) { - uint8_t watch_mask = (addr & 0x03) + size; - - if (watch_mask > 0x04) - return LLDB_INVALID_INDEX32; - else if (watch_mask <= 0x02) - size = 2; - else if (watch_mask <= 0x04) - size = 4; - - addr = addr & (~0x03); + // Iterate over stored watchpoints and find a free or duplicate wp_index + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if ((m_hwp_regs[i].control & 1) == 0) { + wp_index = i; // Mark last free slot + } else if (m_hwp_regs[i].address == addr) { + wp_index = i; // Mark duplicate index + break; // Stop searching here + } } - // We can only watch up to four bytes that follow a 4 byte aligned address - // per watchpoint register pair, so make sure we can properly encode this. - addr_word_offset = addr % 4; - byte_mask = ((1u << size) - 1u) << addr_word_offset; + // No vaccant slot available and no duplicate slot found. + if (wp_index == LLDB_INVALID_INDEX32) + return LLDB_INVALID_INDEX32; - // Check if we need multiple watchpoint register - if (byte_mask > 0xfu) + // There is no need to update watchpoint registers + // if requested byte range is already covered by exiting watchpoint. + if (m_hwp_regs[wp_index].control & 1) { + uint32_t current_size = GetWatchpointSize(wp_index); + if ((current_size == 4) || (current_size == 2 && watch_mask <= 2) || + (current_size == 1 && watch_mask == 1)) + return wp_index; + + if (watch_mask > 2) + size = 4; + else if (watch_mask <= 2) + size = 2; + } + else if (watch_mask > 2) + size = 4; + else if (watch_mask == 2) + size = 2; + else if (watch_mask == 1) + size = 1; + else return LLDB_INVALID_INDEX32; // Setup control value + // Create byte mask for control register // Make the byte_mask into a valid Byte Address Select mask - control_value = byte_mask << 5; + control_value = ((1u << size) - 1u) << 5; // Turn on appropriate watchpoint flags read or write control_value |= (watch_flags << 3); @@ -567,45 +582,19 @@ // Enable this watchpoint and make it stop in privileged or user mode; control_value |= 7; - // Make sure bits 1:0 are clear in our address - addr &= ~((lldb::addr_t)3); + // 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; - // Iterate over stored watchpoints - // Find a free wp_index or update reference count if duplicate. - wp_index = LLDB_INVALID_INDEX32; - for (uint32_t i = 0; i < m_max_hwp_supported; i++) { - if ((m_hwp_regs[i].control & 1) == 0) { - wp_index = i; // Mark last free slot - } else if (m_hwp_regs[i].address == addr && - m_hwp_regs[i].control == control_value) { - wp_index = i; // Mark duplicate index - break; // Stop searching here - } - } - - if (wp_index == LLDB_INVALID_INDEX32) - return LLDB_INVALID_INDEX32; + // PTRACE call to set corresponding watchpoint register. + error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); - // Add new or update existing watchpoint - 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; - - // PTRACE call to set corresponding watchpoint register. - error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); - - if (error.Fail()) { - m_hwp_regs[wp_index].address = 0; - m_hwp_regs[wp_index].control &= ~1; - m_hwp_regs[wp_index].refcount = 0; + if (error.Fail()) { + m_hwp_regs[wp_index].control &= ~1; - return LLDB_INVALID_INDEX32; - } - } else - m_hwp_regs[wp_index].refcount++; + return LLDB_INVALID_INDEX32; + } return wp_index; } @@ -628,36 +617,25 @@ if (wp_index >= m_max_hwp_supported) return false; - // Update reference count if multiple references. - if (m_hwp_regs[wp_index].refcount > 1) { - m_hwp_regs[wp_index].refcount--; - return true; - } else if (m_hwp_regs[wp_index].refcount == 1) { - // Create a backup we can revert to in case of failure. - lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; - uint32_t tempControl = m_hwp_regs[wp_index].control; - uint32_t tempRefCount = m_hwp_regs[wp_index].refcount; - - // Update watchpoint in local cache - m_hwp_regs[wp_index].control &= ~1; - m_hwp_regs[wp_index].address = 0; - m_hwp_regs[wp_index].refcount = 0; - - // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); - - if (error.Fail()) { - m_hwp_regs[wp_index].control = tempControl; - m_hwp_regs[wp_index].address = tempAddr; - m_hwp_regs[wp_index].refcount = tempRefCount; - - return false; - } + // Create a backup we can revert to in case of failure. + lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; + uint32_t tempControl = m_hwp_regs[wp_index].control; + + // Update watchpoint in local cache + m_hwp_regs[wp_index].control &= ~1; + m_hwp_regs[wp_index].address = 0; + + // Ptrace call to update hardware debug registers + error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); + + if (error.Fail()) { + m_hwp_regs[wp_index].control = tempControl; + m_hwp_regs[wp_index].address = tempAddr; - return true; + return false; } - return false; + return true; } Error NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() { @@ -675,19 +653,17 @@ return error; lldb::addr_t tempAddr = 0; - uint32_t tempControl = 0, tempRefCount = 0; + uint32_t tempControl = 0; for (uint32_t i = 0; i < m_max_hwp_supported; i++) { if (m_hwp_regs[i].control & 0x01) { // Create a backup we can revert to in case of failure. tempAddr = m_hwp_regs[i].address; tempControl = m_hwp_regs[i].control; - tempRefCount = m_hwp_regs[i].refcount; // Clear watchpoints in local cache m_hwp_regs[i].control &= ~1; m_hwp_regs[i].address = 0; - m_hwp_regs[i].refcount = 0; // Ptrace call to update hardware debug registers error = WriteHardwareDebugRegs(eDREGTypeWATCH, i); @@ -695,7 +671,6 @@ if (error.Fail()) { m_hwp_regs[i].control = tempControl; m_hwp_regs[i].address = tempAddr; - m_hwp_regs[i].refcount = tempRefCount; return error; } @@ -750,8 +725,8 @@ watch_size = GetWatchpointSize(wp_index); watch_addr = m_hwp_regs[wp_index].address; - if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index) && - trap_addr >= watch_addr && trap_addr < watch_addr + watch_size) { + if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && + trap_addr < watch_addr + watch_size) { m_hwp_regs[wp_index].hit_addr = trap_addr; return Error(); }