breakpoints: use 64-bit type for watchpoint mask and value

This patch changes data types of watchpoint value and mask to allow for
64-bit values match that some architectures (like RISCV) allow.

In addition this patch fixes the behavior of watchpoint command to
zero-out mask if only data value is provided.

Change-Id: I3c7ec1630f03ea9534ec34c0ebe99e08ea56e7f0
Signed-off-by: Parshintsev Anatoly <anatoly.parshintsev@syntacore.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/7840
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Marek Vrbka <marek.vrbka@codasip.com>
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
This commit is contained in:
Parshintsev Anatoly 2023-07-28 20:41:32 +03:00 committed by Tomas Vanek
parent 2ca6d25eb5
commit 2cd8ebf44d
10 changed files with 36 additions and 34 deletions

View File

@ -1779,7 +1779,7 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection,
case 4: case 4:
{ {
if (packet[0] == 'Z') { if (packet[0] == 'Z') {
retval = watchpoint_add(target, address, size, wp_type, 0, 0xffffffffu); retval = watchpoint_add(target, address, size, wp_type, 0, WATCHPOINT_IGNORE_DATA_VALUE_MASK);
if (retval == ERROR_NOT_IMPLEMENTED) { if (retval == ERROR_NOT_IMPLEMENTED) {
/* Send empty reply to report that watchpoints of this type are not supported */ /* Send empty reply to report that watchpoints of this type are not supported */
gdb_put_packet(connection, "", 0); gdb_put_packet(connection, "", 0);

View File

@ -451,6 +451,7 @@ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watch
struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
int rw_mask = 1; int rw_mask = 1;
uint32_t mask; uint32_t mask;
const uint32_t wp_data_mask = watchpoint->mask;
mask = watchpoint->length - 1; mask = watchpoint->length - 1;
@ -469,8 +470,8 @@ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watch
watchpoint->address); watchpoint->address);
embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], mask);
embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK],
watchpoint->mask); wp_data_mask);
if (watchpoint->mask != 0xffffffffu) if (wp_data_mask != (uint32_t)WATCHPOINT_IGNORE_DATA_VALUE_MASK)
embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_VALUE], embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_VALUE],
watchpoint->value); watchpoint->value);
embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK],
@ -488,8 +489,8 @@ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watch
watchpoint->address); watchpoint->address);
embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], mask);
embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK],
watchpoint->mask); wp_data_mask);
if (watchpoint->mask != 0xffffffffu) if (wp_data_mask != (uint32_t)WATCHPOINT_IGNORE_DATA_VALUE_MASK)
embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_VALUE], embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_VALUE],
watchpoint->value); watchpoint->value);
embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK],

View File

@ -918,7 +918,7 @@ static int dpm_watchpoint_setup(struct arm_dpm *dpm, unsigned index_t,
uint32_t control; uint32_t control;
/* this hardware doesn't support data value matching or masking */ /* this hardware doesn't support data value matching or masking */
if (wp->value || wp->mask != ~(uint32_t)0) { if (wp->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) {
LOG_DEBUG("watchpoint values and masking not supported"); LOG_DEBUG("watchpoint values and masking not supported");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} }

View File

@ -1210,7 +1210,7 @@ static int dpmv8_watchpoint_setup(struct arm_dpm *dpm, unsigned index_t,
uint32_t control; uint32_t control;
/* this hardware doesn't support data value matching or masking */ /* this hardware doesn't support data value matching or masking */
if (wp->value || wp->mask != ~(uint32_t)0) { if (wp->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) {
LOG_DEBUG("watchpoint values and masking not supported"); LOG_DEBUG("watchpoint values and masking not supported");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} }

View File

@ -393,7 +393,7 @@ struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
} }
static int watchpoint_add_internal(struct target *target, target_addr_t address, static int watchpoint_add_internal(struct target *target, target_addr_t address,
uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask) uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
{ {
struct watchpoint *watchpoint = target->watchpoints; struct watchpoint *watchpoint = target->watchpoints;
struct watchpoint **watchpoint_p = &target->watchpoints; struct watchpoint **watchpoint_p = &target->watchpoints;
@ -460,7 +460,7 @@ bye:
} }
int watchpoint_add(struct target *target, target_addr_t address, int watchpoint_add(struct target *target, target_addr_t address,
uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask) uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
{ {
if (target->smp) { if (target->smp) {
struct target_list *head; struct target_list *head;

View File

@ -36,11 +36,13 @@ struct breakpoint {
int linked_brp; int linked_brp;
}; };
#define WATCHPOINT_IGNORE_DATA_VALUE_MASK (~(uint64_t)0)
struct watchpoint { struct watchpoint {
target_addr_t address; target_addr_t address;
uint32_t length; uint32_t length;
uint32_t mask; uint64_t mask;
uint32_t value; uint64_t value;
enum watchpoint_rw rw; enum watchpoint_rw rw;
bool is_set; bool is_set;
unsigned int number; unsigned int number;
@ -69,7 +71,7 @@ static inline void breakpoint_hw_set(struct breakpoint *breakpoint, unsigned int
void watchpoint_clear_target(struct target *target); void watchpoint_clear_target(struct target *target);
int watchpoint_add(struct target *target, int watchpoint_add(struct target *target,
target_addr_t address, uint32_t length, target_addr_t address, uint32_t length,
enum watchpoint_rw rw, uint32_t value, uint32_t mask); enum watchpoint_rw rw, uint64_t value, uint64_t mask);
void watchpoint_remove(struct target *target, target_addr_t address); void watchpoint_remove(struct target *target, target_addr_t address);
/* report type and address of just hit watchpoint */ /* report type and address of just hit watchpoint */

View File

@ -2046,8 +2046,14 @@ int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} }
/* hardware doesn't support data value masking */ /* REVISIT This DWT may well be able to watch for specific data
if (watchpoint->mask != ~(uint32_t)0) { * values. Requires comparator #1 to set DATAVMATCH and match
* the data, and another comparator (DATAVADDR0) matching addr.
*
* NOTE: hardware doesn't support data value masking, so we'll need
* to check that mask is zero
*/
if (watchpoint->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) {
LOG_TARGET_DEBUG(target, "watchpoint value masks not supported"); LOG_TARGET_DEBUG(target, "watchpoint value masks not supported");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} }
@ -2068,18 +2074,6 @@ int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} }
/* Caller doesn't seem to be able to describe watching for data
* values of zero; that flags "no value".
*
* REVISIT This DWT may well be able to watch for specific data
* values. Requires comparator #1 to set DATAVMATCH and match
* the data, and another comparator (DATAVADDR0) matching addr.
*/
if (watchpoint->value) {
LOG_TARGET_DEBUG(target, "data value watchpoint not YET supported");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
cortex_m->dwt_comp_available--; cortex_m->dwt_comp_available--;
LOG_TARGET_DEBUG(target, "dwt_comp_available: %d", cortex_m->dwt_comp_available); LOG_TARGET_DEBUG(target, "dwt_comp_available: %d", cortex_m->dwt_comp_available);

View File

@ -4061,8 +4061,8 @@ COMMAND_HANDLER(handle_wp_command)
while (watchpoint) { while (watchpoint) {
command_print(CMD, "address: " TARGET_ADDR_FMT command_print(CMD, "address: " TARGET_ADDR_FMT
", len: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32
", r/w/a: %i, value: 0x%8.8" PRIx32 ", r/w/a: %i, value: 0x%8.8" PRIx64
", mask: 0x%8.8" PRIx32, ", mask: 0x%8.8" PRIx64,
watchpoint->address, watchpoint->address,
watchpoint->length, watchpoint->length,
(int)watchpoint->rw, (int)watchpoint->rw,
@ -4076,15 +4076,20 @@ COMMAND_HANDLER(handle_wp_command)
enum watchpoint_rw type = WPT_ACCESS; enum watchpoint_rw type = WPT_ACCESS;
target_addr_t addr = 0; target_addr_t addr = 0;
uint32_t length = 0; uint32_t length = 0;
uint32_t data_value = 0x0; uint64_t data_value = 0x0;
uint32_t data_mask = 0xffffffff; uint64_t data_mask = WATCHPOINT_IGNORE_DATA_VALUE_MASK;
bool mask_specified = false;
switch (CMD_ARGC) { switch (CMD_ARGC) {
case 5: case 5:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], data_mask); COMMAND_PARSE_NUMBER(u64, CMD_ARGV[4], data_mask);
mask_specified = true;
/* fall through */ /* fall through */
case 4: case 4:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], data_value); COMMAND_PARSE_NUMBER(u64, CMD_ARGV[3], data_value);
// if user specified only data value without mask - the mask should be 0
if (!mask_specified)
data_mask = 0;
/* fall through */ /* fall through */
case 3: case 3:
switch (CMD_ARGV[2][0]) { switch (CMD_ARGV[2][0]) {

View File

@ -2296,7 +2296,7 @@ static int xscale_add_watchpoint(struct target *target,
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} }
if (watchpoint->value) if (watchpoint->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK)
LOG_WARNING("xscale does not support value, mask arguments; ignoring"); LOG_WARNING("xscale does not support value, mask arguments; ignoring");
/* check that length is a power of two */ /* check that length is a power of two */

View File

@ -2570,7 +2570,7 @@ int xtensa_watchpoint_add(struct target *target, struct watchpoint *watchpoint)
return ERROR_TARGET_NOT_HALTED; return ERROR_TARGET_NOT_HALTED;
} }
if (watchpoint->mask != ~(uint32_t)0) { if (watchpoint->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) {
LOG_TARGET_ERROR(target, "watchpoint value masks not supported"); LOG_TARGET_ERROR(target, "watchpoint value masks not supported");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} }