TCF Agent: fixed: sometimes, Linux agent fails to step over hardware data breakpoint and it is triggered second time
diff --git a/agent/machine/arm/tcf/cpudefs-mdep.c b/agent/machine/arm/tcf/cpudefs-mdep.c
index 5baed2b..67c64e9 100644
--- a/agent/machine/arm/tcf/cpudefs-mdep.c
+++ b/agent/machine/arm/tcf/cpudefs-mdep.c
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013, 2015 Stanislav Yakovlev and others.
+ * Copyright (c) 2013, 2016 Stanislav Yakovlev and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * and Eclipse Distribution License v1.0 which accompany this distribution.
@@ -32,6 +32,7 @@
 #  include <sys/auxv.h>
 #  include <asm/hwcap.h>
 #endif
+#include <sys/ptrace.h>
 #include <tcf/framework/errors.h>
 #include <tcf/framework/cpudefs.h>
 #include <tcf/framework/context.h>
@@ -87,8 +88,6 @@
 static RegisterDefinition * lr_def = NULL;
 static RegisterDefinition * cpsr_def = NULL;
 
-#include <sys/ptrace.h>
-
 #if !defined(PTRACE_GETHBPREGS)
 #define PTRACE_GETHBPREGS (enum __ptrace_request)29
 #endif
@@ -125,6 +124,8 @@
     ContextBreakpoint * hw_bps[MAX_HW_BPS];
     unsigned hw_bps_generation;
 
+    ContextAddress skip_wp_addr;
+    unsigned skip_wp_set;
     unsigned armed;
 #endif
 } ContextExtensionARM;
@@ -169,10 +170,18 @@
 
 static void clear_bp(ContextBreakpoint * bp) {
     unsigned i;
-    Context * ctx = bp->ctx;
-    ContextExtensionARM * bps = EXT(ctx);
+    ContextExtensionARM * bps = EXT(bp->ctx);
     for (i = 0; i < MAX_HW_BPS; i++) {
-        if (bps->hw_bps[i] == bp) bps->hw_bps[i] = NULL;
+        if (bps->hw_bps[i] == bp) {
+            LINK * l;
+            bps->hw_bps[i] = NULL;
+            for (l = context_root.next; l != &context_root; l = l->next) {
+                Context * ctx = ctxl2ctxp(l);
+                if (bp->ctx == context_get_group(ctx, CONTEXT_GROUP_BREAKPOINT)) {
+                    EXT(ctx)->skip_wp_set &= ~(1u << i);
+                }
+            }
+        }
     }
 }
 
@@ -199,17 +208,6 @@
     return 0;
 }
 
-static int is_triggered(Context * ctx, ContextBreakpoint * cb) {
-    if (ctx->stopped_by_cb != NULL) {
-        unsigned i = 0;
-        while (ctx->stopped_by_cb[i] != NULL) {
-            if (ctx->stopped_by_cb[i] == cb) return 1;
-            i++;
-        }
-    }
-    return 0;
-}
-
 static int set_debug_regs(Context * ctx, int * step_over_hw_bp) {
     int i, j;
     ContextAddress pc = 0;
@@ -245,7 +243,7 @@
                 /* Skipping the breakpoint */
                 *step_over_hw_bp = 1;
             }
-            else if (bps->arch >= ARM_DEBUG_ARCH_V7_ECP14 && i >= bps->bp_cnt && is_triggered(ctx, cb)) {
+            else if (bps->arch >= ARM_DEBUG_ARCH_V7_ECP14 && (ext->skip_wp_set & (1u << i))) {
                 /* Skipping the watchpoint */
                 *step_over_hw_bp = 1;
             }
@@ -303,8 +301,10 @@
 
 static int disable_hw_stepping_mode(Context * ctx) {
     ContextExtensionARM * ext = EXT(ctx);
-    ext->hw_stepping = 0;
-    ext->hw_bps_regs_generation--;
+    if (ext->hw_stepping) {
+        ext->hw_stepping = 0;
+        ext->hw_bps_regs_generation--;
+    }
     return 0;
 }
 
@@ -395,45 +395,52 @@
     unsigned cb_cnt = 0;
     ContextExtensionARM * ext = EXT(ctx);
     ContextExtensionARM * bps = EXT(context_get_group(ctx, CONTEXT_GROUP_BREAKPOINT));
-    int i;
 
     if (ctx->exiting) return 0;
 
-    if (bps->bp_cnt > 0) {
+    if (bps->bp_cnt > 0 || bps->wp_cnt > 0) {
+        int i;
         ContextAddress pc = 0;
-        if (read_reg(ctx, pc_def, pc_def->size, &pc) < 0) return -1;
-        for (i = 0; i < bps->bp_cnt; i++) {
-            ContextBreakpoint * cb = bps->hw_bps[i];
-            if (cb != NULL && cb->address == pc && (ext->armed & (1u << i))) {
-                ext->triggered_hw_bps[cb_cnt++] = cb;
-            }
-        }
-    }
 
-    if (bps->wp_cnt > 0) {
-        siginfo_t siginfo;
-        pid_t pid = id2pid(ctx->id, NULL);
-        if (ptrace(PTRACE_GETSIGINFO, pid, 0, &siginfo) < 0) return -1;
-        if (siginfo.si_signo == SIGTRAP && (siginfo.si_code & 0xffff) == 0x0004 && siginfo.si_errno < 0) {
-            /* Watchpoint */
-            for (i = bps->bp_cnt; i < bps->bp_cnt + bps->wp_cnt; i++) {
+        if (read_reg(ctx, pc_def, pc_def->size, &pc) < 0) return -1;
+        if (ext->skip_wp_addr != pc) ext->skip_wp_set = 0;
+
+        if (bps->bp_cnt > 0) {
+            for (i = 0; i < bps->bp_cnt; i++) {
                 ContextBreakpoint * cb = bps->hw_bps[i];
-                if (cb != NULL && (ext->armed & (1u << i))) {
-                    if (bps->wp_cnt > 1) {
-                        ContextAddress addr = (ContextAddress)siginfo.si_addr;
-                        if (addr < cb->address || addr >= cb->address + cb->length) continue;
-                    }
+                if (cb != NULL && cb->address == pc && (ext->armed & (1u << i))) {
                     ext->triggered_hw_bps[cb_cnt++] = cb;
                 }
             }
         }
+
+        if (bps->wp_cnt > 0) {
+            siginfo_t siginfo;
+            pid_t pid = id2pid(ctx->id, NULL);
+            if (ptrace(PTRACE_GETSIGINFO, pid, 0, &siginfo) < 0) return -1;
+            if (siginfo.si_signo == SIGTRAP && (siginfo.si_code & 0xffff) == 0x0004 && siginfo.si_errno < 0) {
+                /* Watchpoint */
+                for (i = bps->bp_cnt; i < bps->bp_cnt + bps->wp_cnt; i++) {
+                    ContextBreakpoint * cb = bps->hw_bps[i];
+                    if (cb != NULL && (ext->armed & (1u << i))) {
+                        if (bps->wp_cnt > 1) {
+                            ContextAddress addr = (ContextAddress)siginfo.si_addr;
+                            if (addr < cb->address || addr >= cb->address + cb->length) continue;
+                        }
+                        ext->triggered_hw_bps[cb_cnt++] = cb;
+                        ext->skip_wp_set |= 1u << i;
+                        ext->skip_wp_addr = pc;
+                    }
+                }
+            }
+        }
+        if (cb_cnt > 0) {
+            ctx->stopped_by_cb = ext->triggered_hw_bps;
+            ctx->stopped_by_cb[cb_cnt] = NULL;
+        }
     }
 
     *triggered = cb_cnt > 0;
-    if (cb_cnt > 0) {
-        ctx->stopped_by_cb = ext->triggered_hw_bps;
-        ctx->stopped_by_cb[cb_cnt] = NULL;
-    }
     return 0;
 }
 
@@ -1001,8 +1008,8 @@
 }
 
 void ini_cpudefs_mdep(void) {
-    ini_reg_defs();
     context_extension_offset = context_extension(sizeof(ContextExtensionARM));
+    ini_reg_defs();
 }
 
 #endif
diff --git a/agent/machine/x86_64/tcf/cpudefs-mdep.c b/agent/machine/x86_64/tcf/cpudefs-mdep.c
index e7077d7..a57ace5 100644
--- a/agent/machine/x86_64/tcf/cpudefs-mdep.c
+++ b/agent/machine/x86_64/tcf/cpudefs-mdep.c
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2014-2015 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2016 Wind River Systems, Inc. and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * and Eclipse Distribution License v1.0 which accompany this distribution.
@@ -1327,33 +1327,34 @@
 }
 
 int cpu_bp_on_suspend(Context * ctx, int * triggered) {
-    int cb_found = 0;
+    unsigned cb_cnt = 0;
     uint8_t dr6 = 0;
 
     if (ctx->exiting) return 0;
     if (context_read_reg(ctx, get_DR_definition(6), 0, sizeof(dr6), &dr6) < 0) return -1;
 
     if (dr6 & 0xfu) {
-        int i, j = 0;
+        int i;
         ContextExtensionX86 * ext = EXT(ctx);
         ContextExtensionX86 * bps = EXT(context_get_group(ctx, CONTEXT_GROUP_BREAKPOINT));
         for (i = 0; i < MAX_HW_BPS; i++) {
             if (dr6 & ((uint32_t)1 << i)) {
                 ContextBreakpoint * bp = bps->hw_bps[i];
                 if (bp == NULL) continue;
-                cb_found = 1;
                 if (bp->access_types == (CTX_BP_ACCESS_DATA_READ | CTX_BP_ACCESS_VIRTUAL)) {
                     if (skip_read_only_breakpoint(ctx, dr6, bp)) continue;
                 }
-                ctx->stopped_by_cb = ext->triggered_hw_bps;
-                ctx->stopped_by_cb[j++] = bp;
-                ctx->stopped_by_cb[j] = NULL;
+                ext->triggered_hw_bps[cb_cnt++] = bp;
             }
         }
         dr6 = 0;
         if (context_write_reg(ctx, get_DR_definition(6), 0, sizeof(dr6), &dr6) < 0) return -1;
+        if (cb_cnt > 0) {
+            ctx->stopped_by_cb = ext->triggered_hw_bps;
+            ctx->stopped_by_cb[cb_cnt] = NULL;
+        }
     }
-    *triggered = cb_found;
+    *triggered = cb_cnt > 0;
     return 0;
 }