pkarashchenko commented on code in PR #11350:
URL: https://github.com/apache/nuttx/pull/11350#discussion_r1420929944


##########
arch/arm/src/armv7-m/arm_dbgmonitor.c:
##########
@@ -0,0 +1,673 @@
+/****************************************************************************
+ * arch/arm/src/armv7-m/arm_dbgmonitor.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/arch.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include "nvic.h"
+#include "fpb.h"
+#include "dwt.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* 4 watchpoint, 4 breakpoint, 1 single step */
+
+#define ARM_DEBUG_MAX (4 + 4 + 1)
+
+#define ARM_FPB_NUM() \
+        (((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE2_MASK) >> \
+          FPB_CTRL_NUM_CODE2_SHIFT << FPB_CTRL_NUM_CODE1_SHIFT) | \
+         ((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE1_MASK) >> \
+          FPB_CTRL_NUM_CODE1_SHIFT))
+
+#define ARM_FPB_REVISION() \
+        ((getreg32(FPB_CTRL) & FPB_CTRL_REV_MASK) >> FPB_CTRL_REV_SHIFT)
+
+#define ARM_DWT_NUM() \
+        ((getreg32(DWT_CTRL) & DWT_CTRL_NUMCOMP_MASK) >> \
+         DWT_CTRL_NUMCOMP_SHIFT)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct arm_debug_s
+{
+  int type;
+  void *addr;
+  size_t size;
+  debug_callback_t callback;
+  void *arg;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct arm_debug_s g_arm_debug[ARM_DEBUG_MAX];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_fpb_init
+ ****************************************************************************/
+
+static void arm_fpb_init(void)
+{
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, FPB_COMP0 + i * 4);
+    }
+
+  modifyreg32(FPB_CTRL, 0, FPB_CTRL_ENABLE_MASK | FPB_CTRL_KEY_MASK);
+}
+
+/****************************************************************************
+ * Name: arm_dwt_init
+ ****************************************************************************/
+
+static void arm_dwt_init(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+    }
+}
+
+/****************************************************************************
+ * Name: up_watchpoint_add
+ *
+ * Description:
+ *   Add a watchpoint on the address.
+ *
+ * Input Parameters:
+ *  type - The type of the watchpoint
+ *  addr - The address to be watched
+ *  size - The size of the address to be watched
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ * Notes:
+ *  The size of the watchpoint is determined by the hardware.
+ *  armv7-m supports only support 4 bytes.
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_add(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = 0;
+
+      if (getreg32(DWT_COMP0 + 16 * i) == 0)
+        {
+          switch (type)
+            {
+              case DEBUGPOINT_WATCHPOINT_RO:
+                fun |= DWT_FUNCTION_WATCHPOINT_RO;

Review Comment:
   What is the benefit of `uint32_t fun = 0;` + `fun |= 
DWT_FUNCTION_WATCHPOINT_RO;` vs `uint32_t fun` + `fun = 
DWT_FUNCTION_WATCHPOINT_RO;`?



##########
arch/arm/src/armv7-m/arm_dbgmonitor.c:
##########
@@ -0,0 +1,673 @@
+/****************************************************************************
+ * arch/arm/src/armv7-m/arm_dbgmonitor.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/arch.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include "nvic.h"
+#include "fpb.h"
+#include "dwt.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* 4 watchpoint, 4 breakpoint, 1 single step */
+
+#define ARM_DEBUG_MAX (4 + 4 + 1)
+
+#define ARM_FPB_NUM() \
+        (((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE2_MASK) >> \
+          FPB_CTRL_NUM_CODE2_SHIFT << FPB_CTRL_NUM_CODE1_SHIFT) | \
+         ((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE1_MASK) >> \
+          FPB_CTRL_NUM_CODE1_SHIFT))
+
+#define ARM_FPB_REVISION() \
+        ((getreg32(FPB_CTRL) & FPB_CTRL_REV_MASK) >> FPB_CTRL_REV_SHIFT)
+
+#define ARM_DWT_NUM() \
+        ((getreg32(DWT_CTRL) & DWT_CTRL_NUMCOMP_MASK) >> \
+         DWT_CTRL_NUMCOMP_SHIFT)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct arm_debug_s
+{
+  int type;
+  void *addr;
+  size_t size;
+  debug_callback_t callback;
+  void *arg;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct arm_debug_s g_arm_debug[ARM_DEBUG_MAX];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_fpb_init
+ ****************************************************************************/
+
+static void arm_fpb_init(void)
+{
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, FPB_COMP0 + i * 4);
+    }
+
+  modifyreg32(FPB_CTRL, 0, FPB_CTRL_ENABLE_MASK | FPB_CTRL_KEY_MASK);
+}
+
+/****************************************************************************
+ * Name: arm_dwt_init
+ ****************************************************************************/
+
+static void arm_dwt_init(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+    }
+}
+
+/****************************************************************************
+ * Name: up_watchpoint_add
+ *
+ * Description:
+ *   Add a watchpoint on the address.
+ *
+ * Input Parameters:
+ *  type - The type of the watchpoint
+ *  addr - The address to be watched
+ *  size - The size of the address to be watched
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ * Notes:
+ *  The size of the watchpoint is determined by the hardware.
+ *  armv7-m supports only support 4 bytes.
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_add(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = 0;
+
+      if (getreg32(DWT_COMP0 + 16 * i) == 0)
+        {
+          switch (type)
+            {
+              case DEBUGPOINT_WATCHPOINT_RO:
+                fun |= DWT_FUNCTION_WATCHPOINT_RO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_WO:
+                fun |= DWT_FUNCTION_WATCHPOINT_WO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_RW:
+                fun |= DWT_FUNCTION_WATCHPOINT_RW;
+                break;
+              default:
+                return -EINVAL;
+            }
+
+          putreg32(fun, DWT_FUNCTION0 + 16 * i);
+          putreg32(addr, DWT_COMP0 + 16 * i);
+          putreg32(0, DWT_MASK0 + 16 * i);
+          return 0;
+        }
+    }
+
+  return -ENOSPC;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_remove
+ *
+ * Description:
+ *   Remove a watchpoint on the address.
+ *
+ * Input Parameters:
+ *   type - The type of the watchpoint.
+ *   addr - The address to be watched.
+ *   size - The size of the address to be watched.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_remove(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun_type = (getreg32(DWT_FUNCTION0 + 16 * i) &
+                          DWT_FUNCTION_FUNCTION_MASK) >>
+                          DWT_FUNCTION_FUNCTION_SHIFT;
+
+      switch (fun_type)
+        {
+          case DWT_FUNCTION_WATCHPOINT_RO:
+            if (type == DEBUGPOINT_WATCHPOINT_RO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_WO:
+            if (type == DEBUGPOINT_WATCHPOINT_WO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_RW:
+            if (type == DEBUGPOINT_WATCHPOINT_RW)
+              {
+                break;
+              }
+
+            continue;
+
+          default:
+            continue;
+        }
+
+      if (getreg32(DWT_COMP0 + 16 * i) != addr)
+        {
+          continue;
+        }
+
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      return 0;
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_match
+ *
+ * Description:
+ *   This function will be called when watchpoint match.
+ *
+ ****************************************************************************/
+
+static void arm_watchpoint_match(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t addr = 0;
+  uint32_t i;
+  int type = 0;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = getreg32(DWT_FUNCTION0 + 16 * i);
+      if (fun & DWT_FUNCTION_MATCHED_MASK)
+        {
+          uint32_t fun_type = (fun & DWT_FUNCTION_FUNCTION_MASK) >>
+                              DWT_FUNCTION_FUNCTION_SHIFT;
+
+          addr = getreg32(DWT_COMP0 + 16 * i);
+          switch (fun_type)
+            {
+              case DWT_FUNCTION_WATCHPOINT_RO:
+                  type = DEBUGPOINT_WATCHPOINT_RO;
+                  break;
+              case DWT_FUNCTION_WATCHPOINT_WO:
+                  type = DEBUGPOINT_WATCHPOINT_WO;
+                  break;
+              case DWT_FUNCTION_WATCHPOINT_RW:
+                  type = DEBUGPOINT_WATCHPOINT_RW;
+                  break;

Review Comment:
   ```suggestion
                 case DWT_FUNCTION_WATCHPOINT_RW:
                   type = DEBUGPOINT_WATCHPOINT_RW;
                   break;
   ```



##########
arch/arm/src/armv7-m/arm_dbgmonitor.c:
##########
@@ -0,0 +1,673 @@
+/****************************************************************************
+ * arch/arm/src/armv7-m/arm_dbgmonitor.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/arch.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include "nvic.h"
+#include "fpb.h"
+#include "dwt.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* 4 watchpoint, 4 breakpoint, 1 single step */
+
+#define ARM_DEBUG_MAX (4 + 4 + 1)
+
+#define ARM_FPB_NUM() \
+        (((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE2_MASK) >> \
+          FPB_CTRL_NUM_CODE2_SHIFT << FPB_CTRL_NUM_CODE1_SHIFT) | \
+         ((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE1_MASK) >> \
+          FPB_CTRL_NUM_CODE1_SHIFT))
+
+#define ARM_FPB_REVISION() \
+        ((getreg32(FPB_CTRL) & FPB_CTRL_REV_MASK) >> FPB_CTRL_REV_SHIFT)
+
+#define ARM_DWT_NUM() \
+        ((getreg32(DWT_CTRL) & DWT_CTRL_NUMCOMP_MASK) >> \
+         DWT_CTRL_NUMCOMP_SHIFT)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct arm_debug_s
+{
+  int type;
+  void *addr;
+  size_t size;
+  debug_callback_t callback;
+  void *arg;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct arm_debug_s g_arm_debug[ARM_DEBUG_MAX];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_fpb_init
+ ****************************************************************************/
+
+static void arm_fpb_init(void)
+{
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, FPB_COMP0 + i * 4);
+    }
+
+  modifyreg32(FPB_CTRL, 0, FPB_CTRL_ENABLE_MASK | FPB_CTRL_KEY_MASK);
+}
+
+/****************************************************************************
+ * Name: arm_dwt_init
+ ****************************************************************************/
+
+static void arm_dwt_init(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+    }
+}
+
+/****************************************************************************
+ * Name: up_watchpoint_add
+ *
+ * Description:
+ *   Add a watchpoint on the address.
+ *
+ * Input Parameters:
+ *  type - The type of the watchpoint
+ *  addr - The address to be watched
+ *  size - The size of the address to be watched
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ * Notes:
+ *  The size of the watchpoint is determined by the hardware.
+ *  armv7-m supports only support 4 bytes.
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_add(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = 0;
+
+      if (getreg32(DWT_COMP0 + 16 * i) == 0)
+        {
+          switch (type)
+            {
+              case DEBUGPOINT_WATCHPOINT_RO:
+                fun |= DWT_FUNCTION_WATCHPOINT_RO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_WO:
+                fun |= DWT_FUNCTION_WATCHPOINT_WO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_RW:
+                fun |= DWT_FUNCTION_WATCHPOINT_RW;
+                break;
+              default:
+                return -EINVAL;
+            }
+
+          putreg32(fun, DWT_FUNCTION0 + 16 * i);
+          putreg32(addr, DWT_COMP0 + 16 * i);
+          putreg32(0, DWT_MASK0 + 16 * i);
+          return 0;
+        }
+    }
+
+  return -ENOSPC;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_remove
+ *
+ * Description:
+ *   Remove a watchpoint on the address.
+ *
+ * Input Parameters:
+ *   type - The type of the watchpoint.
+ *   addr - The address to be watched.
+ *   size - The size of the address to be watched.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_remove(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun_type = (getreg32(DWT_FUNCTION0 + 16 * i) &
+                          DWT_FUNCTION_FUNCTION_MASK) >>
+                          DWT_FUNCTION_FUNCTION_SHIFT;
+
+      switch (fun_type)
+        {
+          case DWT_FUNCTION_WATCHPOINT_RO:
+            if (type == DEBUGPOINT_WATCHPOINT_RO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_WO:
+            if (type == DEBUGPOINT_WATCHPOINT_WO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_RW:
+            if (type == DEBUGPOINT_WATCHPOINT_RW)
+              {
+                break;
+              }
+
+            continue;
+
+          default:
+            continue;
+        }
+
+      if (getreg32(DWT_COMP0 + 16 * i) != addr)
+        {
+          continue;
+        }
+
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      return 0;
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_match
+ *
+ * Description:
+ *   This function will be called when watchpoint match.
+ *
+ ****************************************************************************/
+
+static void arm_watchpoint_match(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t addr = 0;
+  uint32_t i;
+  int type = 0;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = getreg32(DWT_FUNCTION0 + 16 * i);
+      if (fun & DWT_FUNCTION_MATCHED_MASK)
+        {
+          uint32_t fun_type = (fun & DWT_FUNCTION_FUNCTION_MASK) >>
+                              DWT_FUNCTION_FUNCTION_SHIFT;
+
+          addr = getreg32(DWT_COMP0 + 16 * i);
+          switch (fun_type)
+            {
+              case DWT_FUNCTION_WATCHPOINT_RO:
+                  type = DEBUGPOINT_WATCHPOINT_RO;
+                  break;
+              case DWT_FUNCTION_WATCHPOINT_WO:
+                  type = DEBUGPOINT_WATCHPOINT_WO;
+                  break;
+              case DWT_FUNCTION_WATCHPOINT_RW:
+                  type = DEBUGPOINT_WATCHPOINT_RW;
+                  break;
+
+              default:
+                continue;
+            }
+        }
+    }
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].addr == (void *)addr &&
+          g_arm_debug[i].type == type && g_arm_debug[i].callback)
+        {
+          g_arm_debug[i].callback(g_arm_debug[i].type,
+                                  g_arm_debug[i].addr,
+                                  g_arm_debug[i].size,
+                                  g_arm_debug[i].arg);
+          break;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: arm_breakpoint_add
+ *
+ * Description:
+ *   Add a breakpoint on addr.
+ *
+ * Input Parameters:
+ *  addr - The address to break.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ * Notes:
+ *  1. If breakpoint is already set, it will do nothing.
+ *  2. If all comparators are in use, it will return -1.
+ *  3. When the breakpoint trigger, if enable monitor exception already ,
+ *     will cause a debug monitor exception, otherwise will cause
+ *     a hard fault.
+ *
+ ****************************************************************************/
+
+static int arm_breakpoint_add(uintptr_t addr)
+{
+  uint32_t revision = ARM_FPB_REVISION();
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t fpb_comp;
+  uint32_t replace;
+  uint32_t comp;
+  uint32_t i;
+
+  if (revision == 0)
+    {
+      replace = (addr & 0x2) == 0 ? 1 : 2;
+      fpb_comp = (addr & ~0x3) | FPB_COMP0_ENABLE_MASK |
+                 (replace << FPB_COMP0_REPLACE_SHIFT);
+    }
+  else
+    {
+      fpb_comp = addr | FPB_COMP0_ENABLE_MASK;
+    }
+
+  for (i = 0; i < num; i++)
+    {
+      comp = getreg32(FPB_COMP0 + i * 4);
+
+      if (comp == fpb_comp) /* Already set */
+        {
+          return 0;
+        }
+      else if (comp & FPB_COMP0_ENABLE_MASK) /* Comparators is in use */
+        {
+          continue;
+        }
+      else /* Find a free comparators */
+        {
+          putreg32(fpb_comp, FPB_COMP0 + i * 4);
+          return 0;
+        }
+    }
+
+  return -ENOSPC;
+}
+
+/****************************************************************************
+ * Name: arm_breakpoint_remove
+ *
+ * Description:
+ *   Remove a breakpoint on addr.
+ *
+ * Input Parameters:
+ *  addr - The address to remove.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_breakpoint_remove(uintptr_t addr)
+{
+  uint32_t revision = ARM_FPB_REVISION();
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t fpb_comp;
+  uint32_t replace;
+  uint32_t i;
+
+  if (revision == 0)
+    {
+      replace = (addr & 0x2) == 0 ? 1 : 2;
+      fpb_comp = (addr & ~0x3) | FPB_COMP0_ENABLE_MASK |
+                 (replace << FPB_COMP0_REPLACE_SHIFT);
+    }
+  else
+    {
+      fpb_comp = addr | FPB_COMP0_ENABLE_MASK;
+    }
+
+  for (i = 0; i < num; i++)
+    {
+      if (fpb_comp == getreg32(FPB_COMP0 + i * 4))
+        {
+          putreg32(0, FPB_COMP0 + i * 4);
+          return 0;
+        }
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: arm_breakpoint_match
+ *
+ * Description:
+ *   This function will be called when breakpoint match.
+ *
+ ****************************************************************************/
+
+static void arm_breakpoint_match(uint32_t pc)
+{
+  uint32_t i;
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].type == DEBUGPOINT_BREAKPOINT &&
+          g_arm_debug[i].addr == (void *)pc &&
+          g_arm_debug[i].callback)
+        {
+          g_arm_debug[i].callback(g_arm_debug[i].type,
+                                  g_arm_debug[i].addr,
+                                  g_arm_debug[i].size,
+                                  g_arm_debug[i].arg);
+          break;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: arm_steppoint
+ *
+ * Description:
+ *   Enable/disable single step.
+ *
+ * Input Parameters:
+ *  enable - True: enable single step; False: disable single step.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_steppoint(bool enable)
+{
+  if (enable)
+    {
+      modifyreg32(NVIC_DEMCR, 0, NVIC_DEMCR_MONSTEP);
+    }
+  else
+    {
+      modifyreg32(NVIC_DEMCR, NVIC_DEMCR_MONSTEP, 0);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: arm_steppoint_match
+ *
+ * Description:
+ *   This function will be called when single step match.
+ *
+ ****************************************************************************/
+
+static void arm_steppoint_match(void)
+{
+  uint32_t i;
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].type == DEBUGPOINT_STEPPOINT &&
+          g_arm_debug[i].callback)
+        {
+          g_arm_debug[i].callback(g_arm_debug[i].type,
+                                  g_arm_debug[i].addr,
+                                  g_arm_debug[i].size,
+                                  g_arm_debug[i].arg);
+          break;
+        }
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_debugpoint_add
+ *
+ * Description:
+ *   Add a debugpoint.
+ *
+ * Input Parameters:
+ *   type     - The debugpoint type. optional value:
+ *              DEBUGPOINT_WATCHPOINT_RO - Read only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_WO - Write only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_RW - Read and write watchpoint.
+ *              DEBUGPOINT_BREAKPOINT    - Breakpoint.
+ *              DEBUGPOINT_STEPPOINT     - Single step.
+ *   addr     - The address to be debugged.
+ *   size     - The watchpoint size. only for watchpoint.
+ *   callback - The callback function when debugpoint triggered.
+ *              if NULL, the debugpoint will be removed.
+ *   arg      - The argument of callback function.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+int up_debugpoint_add(int type, void *addr, size_t size,
+                      debug_callback_t callback, void *arg)
+{
+  int ret = -EINVAL;
+  uint32_t i;
+
+  if (type == DEBUGPOINT_BREAKPOINT)
+    {
+      ret = arm_breakpoint_add((uintptr_t)addr);
+
+      /* Thumb mode breakpoint address must be word-aligned */
+
+      addr = (void *)((uintptr_t)addr & ~0x1);
+    }
+  else if (type == DEBUGPOINT_WATCHPOINT_RO ||
+           type == DEBUGPOINT_WATCHPOINT_WO ||
+           type == DEBUGPOINT_WATCHPOINT_RW)
+    {
+      ret = arm_watchpoint_add(type, (uintptr_t)addr, size);
+    }
+  else if (type == DEBUGPOINT_STEPPOINT)
+    {
+      ret = arm_steppoint(true);
+    }
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].type == DEBUGPOINT_NONE)
+        {
+          g_arm_debug[i].type = type;
+          g_arm_debug[i].addr = addr;
+          g_arm_debug[i].size = size;
+          g_arm_debug[i].callback = callback;
+          g_arm_debug[i].arg = arg;
+          break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: up_debugpoint_remove
+ *
+ * Description:
+ *   Remove a debugpoint.
+ *
+ * Input Parameters:
+ *   type     - The debugpoint type. optional value:
+ *              DEBUGPOINT_WATCHPOINT_RO - Read only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_WO - Write only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_RW - Read and write watchpoint.
+ *              DEBUGPOINT_BREAKPOINT    - Breakpoint.
+ *              DEBUGPOINT_STEPPOINT     - Single step.
+ *   addr     - The address to be debugged.
+ *   size     - The watchpoint size. only for watchpoint.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+int up_debugpoint_remove(int type, void *addr, size_t size)
+{
+  int ret = -EINVAL;
+  uint32_t i;
+
+  if (type == DEBUGPOINT_BREAKPOINT)
+    {
+      ret = arm_breakpoint_remove((uintptr_t)addr);
+
+      /* Thumb mode breakpoint address must be word-aligned */
+
+      addr = (void *)((uintptr_t)addr & ~0x1);
+    }
+  else if (type == DEBUGPOINT_WATCHPOINT_RO ||
+           type == DEBUGPOINT_WATCHPOINT_WO ||
+           type == DEBUGPOINT_WATCHPOINT_RW)
+    {
+      ret = arm_watchpoint_remove(type, (uintptr_t)addr, size);
+    }
+  else if (type == DEBUGPOINT_STEPPOINT)
+    {
+      ret = arm_steppoint(false);
+    }
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].type == type &&
+          g_arm_debug[i].size == size &&
+          g_arm_debug[i].addr == addr)
+        {
+          g_arm_debug[i].type = DEBUGPOINT_NONE;
+          break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: arm_enable_dbgmonitor
+ *
+ * Description:
+ *   This function enables the debug monitor exception.
+ *
+ ****************************************************************************/
+
+int arm_enable_dbgmonitor(void)
+{
+  arm_fpb_init();
+  arm_dwt_init();
+  modifyreg32(NVIC_DEMCR, 0, NVIC_DEMCR_MONEN | NVIC_DEMCR_TRCENA);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: arm_dbgmonitor
+ *
+ * Description:
+ *   This is Debug Monitor exception handler.  This function is entered when
+ *   the processor enters debug mode.  The debug monitor handler will handle
+ *   debug events, and resume execution.
+ *
+ ****************************************************************************/
+
+int arm_dbgmonitor(int irq, void *context, void *arg)
+{
+  uint32_t dfsr = getreg32(NVIC_DFAULTS);
+  uint32_t *regs = (uint32_t *)context;
+
+  if (dfsr & NVIC_DFAULTS_HALTED)
+    {
+      arm_steppoint_match();
+    }
+
+  if (dfsr & NVIC_DFAULTS_BKPT)
+    {
+      arm_breakpoint_match(regs[REG_PC]);
+    }
+
+  if (dfsr & NVIC_DFAULTS_DWTTRAP)

Review Comment:
   same



##########
arch/Kconfig:
##########
@@ -499,6 +499,10 @@ config ARCH_HAVE_BACKTRACE
        bool
        default n
 
+config ARCH_HAVE_DEBUG
+       bool "architecture have debug support"

Review Comment:
   ```suggestion
        bool "Architecture have debug support"
   ```



##########
arch/arm/src/armv7-m/arm_dbgmonitor.c:
##########
@@ -0,0 +1,673 @@
+/****************************************************************************
+ * arch/arm/src/armv7-m/arm_dbgmonitor.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/arch.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include "nvic.h"
+#include "fpb.h"
+#include "dwt.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* 4 watchpoint, 4 breakpoint, 1 single step */
+
+#define ARM_DEBUG_MAX (4 + 4 + 1)
+
+#define ARM_FPB_NUM() \
+        (((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE2_MASK) >> \
+          FPB_CTRL_NUM_CODE2_SHIFT << FPB_CTRL_NUM_CODE1_SHIFT) | \
+         ((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE1_MASK) >> \
+          FPB_CTRL_NUM_CODE1_SHIFT))
+
+#define ARM_FPB_REVISION() \
+        ((getreg32(FPB_CTRL) & FPB_CTRL_REV_MASK) >> FPB_CTRL_REV_SHIFT)
+
+#define ARM_DWT_NUM() \
+        ((getreg32(DWT_CTRL) & DWT_CTRL_NUMCOMP_MASK) >> \
+         DWT_CTRL_NUMCOMP_SHIFT)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct arm_debug_s
+{
+  int type;
+  void *addr;
+  size_t size;
+  debug_callback_t callback;
+  void *arg;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct arm_debug_s g_arm_debug[ARM_DEBUG_MAX];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_fpb_init
+ ****************************************************************************/
+
+static void arm_fpb_init(void)
+{
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, FPB_COMP0 + i * 4);
+    }
+
+  modifyreg32(FPB_CTRL, 0, FPB_CTRL_ENABLE_MASK | FPB_CTRL_KEY_MASK);
+}
+
+/****************************************************************************
+ * Name: arm_dwt_init
+ ****************************************************************************/
+
+static void arm_dwt_init(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+    }
+}
+
+/****************************************************************************
+ * Name: up_watchpoint_add
+ *
+ * Description:
+ *   Add a watchpoint on the address.
+ *
+ * Input Parameters:
+ *  type - The type of the watchpoint
+ *  addr - The address to be watched
+ *  size - The size of the address to be watched
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ * Notes:
+ *  The size of the watchpoint is determined by the hardware.
+ *  armv7-m supports only support 4 bytes.
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_add(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = 0;
+
+      if (getreg32(DWT_COMP0 + 16 * i) == 0)
+        {
+          switch (type)
+            {
+              case DEBUGPOINT_WATCHPOINT_RO:
+                fun |= DWT_FUNCTION_WATCHPOINT_RO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_WO:
+                fun |= DWT_FUNCTION_WATCHPOINT_WO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_RW:
+                fun |= DWT_FUNCTION_WATCHPOINT_RW;
+                break;
+              default:
+                return -EINVAL;
+            }
+
+          putreg32(fun, DWT_FUNCTION0 + 16 * i);
+          putreg32(addr, DWT_COMP0 + 16 * i);
+          putreg32(0, DWT_MASK0 + 16 * i);
+          return 0;
+        }
+    }
+
+  return -ENOSPC;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_remove
+ *
+ * Description:
+ *   Remove a watchpoint on the address.
+ *
+ * Input Parameters:
+ *   type - The type of the watchpoint.
+ *   addr - The address to be watched.
+ *   size - The size of the address to be watched.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_remove(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun_type = (getreg32(DWT_FUNCTION0 + 16 * i) &
+                          DWT_FUNCTION_FUNCTION_MASK) >>
+                          DWT_FUNCTION_FUNCTION_SHIFT;
+
+      switch (fun_type)
+        {
+          case DWT_FUNCTION_WATCHPOINT_RO:
+            if (type == DEBUGPOINT_WATCHPOINT_RO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_WO:
+            if (type == DEBUGPOINT_WATCHPOINT_WO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_RW:
+            if (type == DEBUGPOINT_WATCHPOINT_RW)
+              {
+                break;
+              }
+
+            continue;
+
+          default:
+            continue;
+        }
+
+      if (getreg32(DWT_COMP0 + 16 * i) != addr)
+        {
+          continue;
+        }
+
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      return 0;
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_match
+ *
+ * Description:
+ *   This function will be called when watchpoint match.
+ *
+ ****************************************************************************/
+
+static void arm_watchpoint_match(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t addr = 0;
+  uint32_t i;
+  int type = 0;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = getreg32(DWT_FUNCTION0 + 16 * i);
+      if (fun & DWT_FUNCTION_MATCHED_MASK)

Review Comment:
   Optional
   ```suggestion
         if ((fun & DWT_FUNCTION_MATCHED_MASK) != 0)
   ```



##########
arch/arm/src/armv7-m/arm_dbgmonitor.c:
##########
@@ -0,0 +1,673 @@
+/****************************************************************************
+ * arch/arm/src/armv7-m/arm_dbgmonitor.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/arch.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include "nvic.h"
+#include "fpb.h"
+#include "dwt.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* 4 watchpoint, 4 breakpoint, 1 single step */
+
+#define ARM_DEBUG_MAX (4 + 4 + 1)
+
+#define ARM_FPB_NUM() \
+        (((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE2_MASK) >> \
+          FPB_CTRL_NUM_CODE2_SHIFT << FPB_CTRL_NUM_CODE1_SHIFT) | \
+         ((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE1_MASK) >> \
+          FPB_CTRL_NUM_CODE1_SHIFT))
+
+#define ARM_FPB_REVISION() \
+        ((getreg32(FPB_CTRL) & FPB_CTRL_REV_MASK) >> FPB_CTRL_REV_SHIFT)
+
+#define ARM_DWT_NUM() \
+        ((getreg32(DWT_CTRL) & DWT_CTRL_NUMCOMP_MASK) >> \
+         DWT_CTRL_NUMCOMP_SHIFT)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct arm_debug_s
+{
+  int type;
+  void *addr;
+  size_t size;
+  debug_callback_t callback;
+  void *arg;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct arm_debug_s g_arm_debug[ARM_DEBUG_MAX];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_fpb_init
+ ****************************************************************************/
+
+static void arm_fpb_init(void)
+{
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, FPB_COMP0 + i * 4);
+    }
+
+  modifyreg32(FPB_CTRL, 0, FPB_CTRL_ENABLE_MASK | FPB_CTRL_KEY_MASK);
+}
+
+/****************************************************************************
+ * Name: arm_dwt_init
+ ****************************************************************************/
+
+static void arm_dwt_init(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+    }
+}
+
+/****************************************************************************
+ * Name: up_watchpoint_add
+ *
+ * Description:
+ *   Add a watchpoint on the address.
+ *
+ * Input Parameters:
+ *  type - The type of the watchpoint
+ *  addr - The address to be watched
+ *  size - The size of the address to be watched
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ * Notes:
+ *  The size of the watchpoint is determined by the hardware.
+ *  armv7-m supports only support 4 bytes.
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_add(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = 0;
+
+      if (getreg32(DWT_COMP0 + 16 * i) == 0)
+        {
+          switch (type)
+            {
+              case DEBUGPOINT_WATCHPOINT_RO:
+                fun |= DWT_FUNCTION_WATCHPOINT_RO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_WO:
+                fun |= DWT_FUNCTION_WATCHPOINT_WO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_RW:
+                fun |= DWT_FUNCTION_WATCHPOINT_RW;
+                break;
+              default:
+                return -EINVAL;
+            }
+
+          putreg32(fun, DWT_FUNCTION0 + 16 * i);
+          putreg32(addr, DWT_COMP0 + 16 * i);
+          putreg32(0, DWT_MASK0 + 16 * i);
+          return 0;
+        }
+    }
+
+  return -ENOSPC;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_remove
+ *
+ * Description:
+ *   Remove a watchpoint on the address.
+ *
+ * Input Parameters:
+ *   type - The type of the watchpoint.
+ *   addr - The address to be watched.
+ *   size - The size of the address to be watched.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_remove(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun_type = (getreg32(DWT_FUNCTION0 + 16 * i) &
+                          DWT_FUNCTION_FUNCTION_MASK) >>
+                          DWT_FUNCTION_FUNCTION_SHIFT;
+
+      switch (fun_type)
+        {
+          case DWT_FUNCTION_WATCHPOINT_RO:
+            if (type == DEBUGPOINT_WATCHPOINT_RO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_WO:
+            if (type == DEBUGPOINT_WATCHPOINT_WO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_RW:
+            if (type == DEBUGPOINT_WATCHPOINT_RW)
+              {
+                break;
+              }
+
+            continue;
+
+          default:
+            continue;
+        }
+
+      if (getreg32(DWT_COMP0 + 16 * i) != addr)
+        {
+          continue;
+        }
+
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      return 0;
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_match
+ *
+ * Description:
+ *   This function will be called when watchpoint match.
+ *
+ ****************************************************************************/
+
+static void arm_watchpoint_match(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t addr = 0;
+  uint32_t i;
+  int type = 0;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = getreg32(DWT_FUNCTION0 + 16 * i);
+      if (fun & DWT_FUNCTION_MATCHED_MASK)
+        {
+          uint32_t fun_type = (fun & DWT_FUNCTION_FUNCTION_MASK) >>
+                              DWT_FUNCTION_FUNCTION_SHIFT;
+
+          addr = getreg32(DWT_COMP0 + 16 * i);
+          switch (fun_type)
+            {
+              case DWT_FUNCTION_WATCHPOINT_RO:
+                  type = DEBUGPOINT_WATCHPOINT_RO;
+                  break;

Review Comment:
   ```suggestion
                 case DWT_FUNCTION_WATCHPOINT_RO:
                   type = DEBUGPOINT_WATCHPOINT_RO;
                   break;
   ```



##########
arch/arm/src/armv8-m/arm_dbgmonitor.c:
##########
@@ -0,0 +1,700 @@
+/****************************************************************************

Review Comment:
   All the same comments as for armv7



##########
arch/arm/src/armv7-m/arm_dbgmonitor.c:
##########
@@ -0,0 +1,673 @@
+/****************************************************************************
+ * arch/arm/src/armv7-m/arm_dbgmonitor.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/arch.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include "nvic.h"
+#include "fpb.h"
+#include "dwt.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* 4 watchpoint, 4 breakpoint, 1 single step */
+
+#define ARM_DEBUG_MAX (4 + 4 + 1)
+
+#define ARM_FPB_NUM() \
+        (((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE2_MASK) >> \
+          FPB_CTRL_NUM_CODE2_SHIFT << FPB_CTRL_NUM_CODE1_SHIFT) | \
+         ((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE1_MASK) >> \
+          FPB_CTRL_NUM_CODE1_SHIFT))
+
+#define ARM_FPB_REVISION() \
+        ((getreg32(FPB_CTRL) & FPB_CTRL_REV_MASK) >> FPB_CTRL_REV_SHIFT)
+
+#define ARM_DWT_NUM() \
+        ((getreg32(DWT_CTRL) & DWT_CTRL_NUMCOMP_MASK) >> \
+         DWT_CTRL_NUMCOMP_SHIFT)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct arm_debug_s
+{
+  int type;
+  void *addr;
+  size_t size;
+  debug_callback_t callback;
+  void *arg;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct arm_debug_s g_arm_debug[ARM_DEBUG_MAX];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_fpb_init
+ ****************************************************************************/
+
+static void arm_fpb_init(void)
+{
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, FPB_COMP0 + i * 4);
+    }
+
+  modifyreg32(FPB_CTRL, 0, FPB_CTRL_ENABLE_MASK | FPB_CTRL_KEY_MASK);
+}
+
+/****************************************************************************
+ * Name: arm_dwt_init
+ ****************************************************************************/
+
+static void arm_dwt_init(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+    }
+}
+
+/****************************************************************************
+ * Name: up_watchpoint_add
+ *
+ * Description:
+ *   Add a watchpoint on the address.
+ *
+ * Input Parameters:
+ *  type - The type of the watchpoint
+ *  addr - The address to be watched
+ *  size - The size of the address to be watched
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ * Notes:
+ *  The size of the watchpoint is determined by the hardware.
+ *  armv7-m supports only support 4 bytes.
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_add(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = 0;
+
+      if (getreg32(DWT_COMP0 + 16 * i) == 0)
+        {
+          switch (type)
+            {
+              case DEBUGPOINT_WATCHPOINT_RO:
+                fun |= DWT_FUNCTION_WATCHPOINT_RO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_WO:
+                fun |= DWT_FUNCTION_WATCHPOINT_WO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_RW:
+                fun |= DWT_FUNCTION_WATCHPOINT_RW;
+                break;
+              default:
+                return -EINVAL;
+            }
+
+          putreg32(fun, DWT_FUNCTION0 + 16 * i);
+          putreg32(addr, DWT_COMP0 + 16 * i);
+          putreg32(0, DWT_MASK0 + 16 * i);
+          return 0;
+        }
+    }
+
+  return -ENOSPC;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_remove
+ *
+ * Description:
+ *   Remove a watchpoint on the address.
+ *
+ * Input Parameters:
+ *   type - The type of the watchpoint.
+ *   addr - The address to be watched.
+ *   size - The size of the address to be watched.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_remove(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun_type = (getreg32(DWT_FUNCTION0 + 16 * i) &
+                          DWT_FUNCTION_FUNCTION_MASK) >>
+                          DWT_FUNCTION_FUNCTION_SHIFT;
+
+      switch (fun_type)
+        {
+          case DWT_FUNCTION_WATCHPOINT_RO:
+            if (type == DEBUGPOINT_WATCHPOINT_RO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_WO:
+            if (type == DEBUGPOINT_WATCHPOINT_WO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_RW:
+            if (type == DEBUGPOINT_WATCHPOINT_RW)
+              {
+                break;
+              }
+
+            continue;
+
+          default:
+            continue;
+        }
+
+      if (getreg32(DWT_COMP0 + 16 * i) != addr)
+        {
+          continue;
+        }
+
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      return 0;
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_match
+ *
+ * Description:
+ *   This function will be called when watchpoint match.
+ *
+ ****************************************************************************/
+
+static void arm_watchpoint_match(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t addr = 0;
+  uint32_t i;
+  int type = 0;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = getreg32(DWT_FUNCTION0 + 16 * i);
+      if (fun & DWT_FUNCTION_MATCHED_MASK)
+        {
+          uint32_t fun_type = (fun & DWT_FUNCTION_FUNCTION_MASK) >>
+                              DWT_FUNCTION_FUNCTION_SHIFT;
+
+          addr = getreg32(DWT_COMP0 + 16 * i);
+          switch (fun_type)
+            {
+              case DWT_FUNCTION_WATCHPOINT_RO:
+                  type = DEBUGPOINT_WATCHPOINT_RO;
+                  break;
+              case DWT_FUNCTION_WATCHPOINT_WO:
+                  type = DEBUGPOINT_WATCHPOINT_WO;
+                  break;

Review Comment:
   ```suggestion
                 case DWT_FUNCTION_WATCHPOINT_WO:
                   type = DEBUGPOINT_WATCHPOINT_WO;
                   break;
   ```



##########
arch/arm/src/armv7-m/arm_dbgmonitor.c:
##########
@@ -0,0 +1,673 @@
+/****************************************************************************
+ * arch/arm/src/armv7-m/arm_dbgmonitor.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/arch.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include "nvic.h"
+#include "fpb.h"
+#include "dwt.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* 4 watchpoint, 4 breakpoint, 1 single step */
+
+#define ARM_DEBUG_MAX (4 + 4 + 1)
+
+#define ARM_FPB_NUM() \
+        (((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE2_MASK) >> \
+          FPB_CTRL_NUM_CODE2_SHIFT << FPB_CTRL_NUM_CODE1_SHIFT) | \
+         ((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE1_MASK) >> \
+          FPB_CTRL_NUM_CODE1_SHIFT))
+
+#define ARM_FPB_REVISION() \
+        ((getreg32(FPB_CTRL) & FPB_CTRL_REV_MASK) >> FPB_CTRL_REV_SHIFT)
+
+#define ARM_DWT_NUM() \
+        ((getreg32(DWT_CTRL) & DWT_CTRL_NUMCOMP_MASK) >> \
+         DWT_CTRL_NUMCOMP_SHIFT)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct arm_debug_s
+{
+  int type;
+  void *addr;
+  size_t size;
+  debug_callback_t callback;
+  void *arg;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct arm_debug_s g_arm_debug[ARM_DEBUG_MAX];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_fpb_init
+ ****************************************************************************/
+
+static void arm_fpb_init(void)
+{
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, FPB_COMP0 + i * 4);
+    }
+
+  modifyreg32(FPB_CTRL, 0, FPB_CTRL_ENABLE_MASK | FPB_CTRL_KEY_MASK);
+}
+
+/****************************************************************************
+ * Name: arm_dwt_init
+ ****************************************************************************/
+
+static void arm_dwt_init(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+    }
+}
+
+/****************************************************************************
+ * Name: up_watchpoint_add
+ *
+ * Description:
+ *   Add a watchpoint on the address.
+ *
+ * Input Parameters:
+ *  type - The type of the watchpoint
+ *  addr - The address to be watched
+ *  size - The size of the address to be watched
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ * Notes:
+ *  The size of the watchpoint is determined by the hardware.
+ *  armv7-m supports only support 4 bytes.
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_add(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = 0;
+
+      if (getreg32(DWT_COMP0 + 16 * i) == 0)
+        {
+          switch (type)
+            {
+              case DEBUGPOINT_WATCHPOINT_RO:
+                fun |= DWT_FUNCTION_WATCHPOINT_RO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_WO:
+                fun |= DWT_FUNCTION_WATCHPOINT_WO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_RW:
+                fun |= DWT_FUNCTION_WATCHPOINT_RW;
+                break;
+              default:
+                return -EINVAL;
+            }
+
+          putreg32(fun, DWT_FUNCTION0 + 16 * i);
+          putreg32(addr, DWT_COMP0 + 16 * i);
+          putreg32(0, DWT_MASK0 + 16 * i);
+          return 0;
+        }
+    }
+
+  return -ENOSPC;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_remove
+ *
+ * Description:
+ *   Remove a watchpoint on the address.
+ *
+ * Input Parameters:
+ *   type - The type of the watchpoint.
+ *   addr - The address to be watched.
+ *   size - The size of the address to be watched.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_remove(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun_type = (getreg32(DWT_FUNCTION0 + 16 * i) &
+                          DWT_FUNCTION_FUNCTION_MASK) >>
+                          DWT_FUNCTION_FUNCTION_SHIFT;
+
+      switch (fun_type)
+        {
+          case DWT_FUNCTION_WATCHPOINT_RO:
+            if (type == DEBUGPOINT_WATCHPOINT_RO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_WO:
+            if (type == DEBUGPOINT_WATCHPOINT_WO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_RW:
+            if (type == DEBUGPOINT_WATCHPOINT_RW)
+              {
+                break;
+              }
+
+            continue;
+
+          default:
+            continue;
+        }
+
+      if (getreg32(DWT_COMP0 + 16 * i) != addr)
+        {
+          continue;
+        }
+
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      return 0;
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_match
+ *
+ * Description:
+ *   This function will be called when watchpoint match.
+ *
+ ****************************************************************************/
+
+static void arm_watchpoint_match(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t addr = 0;
+  uint32_t i;
+  int type = 0;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = getreg32(DWT_FUNCTION0 + 16 * i);
+      if (fun & DWT_FUNCTION_MATCHED_MASK)
+        {
+          uint32_t fun_type = (fun & DWT_FUNCTION_FUNCTION_MASK) >>
+                              DWT_FUNCTION_FUNCTION_SHIFT;
+
+          addr = getreg32(DWT_COMP0 + 16 * i);
+          switch (fun_type)
+            {
+              case DWT_FUNCTION_WATCHPOINT_RO:
+                  type = DEBUGPOINT_WATCHPOINT_RO;
+                  break;
+              case DWT_FUNCTION_WATCHPOINT_WO:
+                  type = DEBUGPOINT_WATCHPOINT_WO;
+                  break;
+              case DWT_FUNCTION_WATCHPOINT_RW:
+                  type = DEBUGPOINT_WATCHPOINT_RW;
+                  break;
+
+              default:
+                continue;
+            }
+        }
+    }
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].addr == (void *)addr &&
+          g_arm_debug[i].type == type && g_arm_debug[i].callback)
+        {
+          g_arm_debug[i].callback(g_arm_debug[i].type,
+                                  g_arm_debug[i].addr,
+                                  g_arm_debug[i].size,
+                                  g_arm_debug[i].arg);
+          break;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: arm_breakpoint_add
+ *
+ * Description:
+ *   Add a breakpoint on addr.
+ *
+ * Input Parameters:
+ *  addr - The address to break.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ * Notes:
+ *  1. If breakpoint is already set, it will do nothing.
+ *  2. If all comparators are in use, it will return -1.
+ *  3. When the breakpoint trigger, if enable monitor exception already ,
+ *     will cause a debug monitor exception, otherwise will cause
+ *     a hard fault.
+ *
+ ****************************************************************************/
+
+static int arm_breakpoint_add(uintptr_t addr)
+{
+  uint32_t revision = ARM_FPB_REVISION();
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t fpb_comp;
+  uint32_t replace;
+  uint32_t comp;
+  uint32_t i;
+
+  if (revision == 0)
+    {
+      replace = (addr & 0x2) == 0 ? 1 : 2;
+      fpb_comp = (addr & ~0x3) | FPB_COMP0_ENABLE_MASK |
+                 (replace << FPB_COMP0_REPLACE_SHIFT);
+    }
+  else
+    {
+      fpb_comp = addr | FPB_COMP0_ENABLE_MASK;
+    }
+
+  for (i = 0; i < num; i++)
+    {
+      comp = getreg32(FPB_COMP0 + i * 4);
+
+      if (comp == fpb_comp) /* Already set */
+        {
+          return 0;
+        }
+      else if (comp & FPB_COMP0_ENABLE_MASK) /* Comparators is in use */
+        {
+          continue;
+        }
+      else /* Find a free comparators */
+        {
+          putreg32(fpb_comp, FPB_COMP0 + i * 4);
+          return 0;
+        }
+    }
+
+  return -ENOSPC;
+}
+
+/****************************************************************************
+ * Name: arm_breakpoint_remove
+ *
+ * Description:
+ *   Remove a breakpoint on addr.
+ *
+ * Input Parameters:
+ *  addr - The address to remove.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_breakpoint_remove(uintptr_t addr)
+{
+  uint32_t revision = ARM_FPB_REVISION();
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t fpb_comp;
+  uint32_t replace;
+  uint32_t i;
+
+  if (revision == 0)
+    {
+      replace = (addr & 0x2) == 0 ? 1 : 2;
+      fpb_comp = (addr & ~0x3) | FPB_COMP0_ENABLE_MASK |
+                 (replace << FPB_COMP0_REPLACE_SHIFT);
+    }
+  else
+    {
+      fpb_comp = addr | FPB_COMP0_ENABLE_MASK;
+    }
+
+  for (i = 0; i < num; i++)
+    {
+      if (fpb_comp == getreg32(FPB_COMP0 + i * 4))
+        {
+          putreg32(0, FPB_COMP0 + i * 4);
+          return 0;
+        }
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: arm_breakpoint_match
+ *
+ * Description:
+ *   This function will be called when breakpoint match.
+ *
+ ****************************************************************************/
+
+static void arm_breakpoint_match(uint32_t pc)
+{
+  uint32_t i;
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].type == DEBUGPOINT_BREAKPOINT &&
+          g_arm_debug[i].addr == (void *)pc &&
+          g_arm_debug[i].callback)
+        {
+          g_arm_debug[i].callback(g_arm_debug[i].type,
+                                  g_arm_debug[i].addr,
+                                  g_arm_debug[i].size,
+                                  g_arm_debug[i].arg);
+          break;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: arm_steppoint
+ *
+ * Description:
+ *   Enable/disable single step.
+ *
+ * Input Parameters:
+ *  enable - True: enable single step; False: disable single step.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_steppoint(bool enable)
+{
+  if (enable)
+    {
+      modifyreg32(NVIC_DEMCR, 0, NVIC_DEMCR_MONSTEP);
+    }
+  else
+    {
+      modifyreg32(NVIC_DEMCR, NVIC_DEMCR_MONSTEP, 0);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: arm_steppoint_match
+ *
+ * Description:
+ *   This function will be called when single step match.
+ *
+ ****************************************************************************/
+
+static void arm_steppoint_match(void)
+{
+  uint32_t i;
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].type == DEBUGPOINT_STEPPOINT &&
+          g_arm_debug[i].callback)

Review Comment:
   Optional
   ```suggestion
             g_arm_debug[i].callback != NULL)
   ```



##########
arch/arm/src/armv7-m/arm_dbgmonitor.c:
##########
@@ -0,0 +1,673 @@
+/****************************************************************************
+ * arch/arm/src/armv7-m/arm_dbgmonitor.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/arch.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include "nvic.h"
+#include "fpb.h"
+#include "dwt.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* 4 watchpoint, 4 breakpoint, 1 single step */
+
+#define ARM_DEBUG_MAX (4 + 4 + 1)
+
+#define ARM_FPB_NUM() \
+        (((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE2_MASK) >> \
+          FPB_CTRL_NUM_CODE2_SHIFT << FPB_CTRL_NUM_CODE1_SHIFT) | \
+         ((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE1_MASK) >> \
+          FPB_CTRL_NUM_CODE1_SHIFT))
+
+#define ARM_FPB_REVISION() \
+        ((getreg32(FPB_CTRL) & FPB_CTRL_REV_MASK) >> FPB_CTRL_REV_SHIFT)
+
+#define ARM_DWT_NUM() \
+        ((getreg32(DWT_CTRL) & DWT_CTRL_NUMCOMP_MASK) >> \
+         DWT_CTRL_NUMCOMP_SHIFT)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct arm_debug_s
+{
+  int type;
+  void *addr;
+  size_t size;
+  debug_callback_t callback;
+  void *arg;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct arm_debug_s g_arm_debug[ARM_DEBUG_MAX];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_fpb_init
+ ****************************************************************************/
+
+static void arm_fpb_init(void)
+{
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, FPB_COMP0 + i * 4);
+    }
+
+  modifyreg32(FPB_CTRL, 0, FPB_CTRL_ENABLE_MASK | FPB_CTRL_KEY_MASK);
+}
+
+/****************************************************************************
+ * Name: arm_dwt_init
+ ****************************************************************************/
+
+static void arm_dwt_init(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+    }
+}
+
+/****************************************************************************
+ * Name: up_watchpoint_add
+ *
+ * Description:
+ *   Add a watchpoint on the address.
+ *
+ * Input Parameters:
+ *  type - The type of the watchpoint
+ *  addr - The address to be watched
+ *  size - The size of the address to be watched
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ * Notes:
+ *  The size of the watchpoint is determined by the hardware.
+ *  armv7-m supports only support 4 bytes.
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_add(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = 0;
+
+      if (getreg32(DWT_COMP0 + 16 * i) == 0)
+        {
+          switch (type)
+            {
+              case DEBUGPOINT_WATCHPOINT_RO:
+                fun |= DWT_FUNCTION_WATCHPOINT_RO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_WO:
+                fun |= DWT_FUNCTION_WATCHPOINT_WO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_RW:
+                fun |= DWT_FUNCTION_WATCHPOINT_RW;
+                break;
+              default:
+                return -EINVAL;
+            }
+
+          putreg32(fun, DWT_FUNCTION0 + 16 * i);
+          putreg32(addr, DWT_COMP0 + 16 * i);
+          putreg32(0, DWT_MASK0 + 16 * i);
+          return 0;
+        }
+    }
+
+  return -ENOSPC;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_remove
+ *
+ * Description:
+ *   Remove a watchpoint on the address.
+ *
+ * Input Parameters:
+ *   type - The type of the watchpoint.
+ *   addr - The address to be watched.
+ *   size - The size of the address to be watched.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_remove(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun_type = (getreg32(DWT_FUNCTION0 + 16 * i) &
+                          DWT_FUNCTION_FUNCTION_MASK) >>
+                          DWT_FUNCTION_FUNCTION_SHIFT;
+
+      switch (fun_type)
+        {
+          case DWT_FUNCTION_WATCHPOINT_RO:
+            if (type == DEBUGPOINT_WATCHPOINT_RO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_WO:
+            if (type == DEBUGPOINT_WATCHPOINT_WO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_RW:
+            if (type == DEBUGPOINT_WATCHPOINT_RW)
+              {
+                break;
+              }
+
+            continue;
+
+          default:
+            continue;
+        }
+
+      if (getreg32(DWT_COMP0 + 16 * i) != addr)
+        {
+          continue;
+        }
+
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      return 0;
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_match
+ *
+ * Description:
+ *   This function will be called when watchpoint match.
+ *
+ ****************************************************************************/
+
+static void arm_watchpoint_match(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t addr = 0;
+  uint32_t i;
+  int type = 0;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = getreg32(DWT_FUNCTION0 + 16 * i);
+      if (fun & DWT_FUNCTION_MATCHED_MASK)
+        {
+          uint32_t fun_type = (fun & DWT_FUNCTION_FUNCTION_MASK) >>
+                              DWT_FUNCTION_FUNCTION_SHIFT;
+
+          addr = getreg32(DWT_COMP0 + 16 * i);
+          switch (fun_type)
+            {
+              case DWT_FUNCTION_WATCHPOINT_RO:
+                  type = DEBUGPOINT_WATCHPOINT_RO;
+                  break;
+              case DWT_FUNCTION_WATCHPOINT_WO:
+                  type = DEBUGPOINT_WATCHPOINT_WO;
+                  break;
+              case DWT_FUNCTION_WATCHPOINT_RW:
+                  type = DEBUGPOINT_WATCHPOINT_RW;
+                  break;
+
+              default:
+                continue;
+            }
+        }
+    }
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].addr == (void *)addr &&
+          g_arm_debug[i].type == type && g_arm_debug[i].callback)
+        {
+          g_arm_debug[i].callback(g_arm_debug[i].type,
+                                  g_arm_debug[i].addr,
+                                  g_arm_debug[i].size,
+                                  g_arm_debug[i].arg);
+          break;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: arm_breakpoint_add
+ *
+ * Description:
+ *   Add a breakpoint on addr.
+ *
+ * Input Parameters:
+ *  addr - The address to break.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ * Notes:
+ *  1. If breakpoint is already set, it will do nothing.
+ *  2. If all comparators are in use, it will return -1.
+ *  3. When the breakpoint trigger, if enable monitor exception already ,
+ *     will cause a debug monitor exception, otherwise will cause
+ *     a hard fault.
+ *
+ ****************************************************************************/
+
+static int arm_breakpoint_add(uintptr_t addr)
+{
+  uint32_t revision = ARM_FPB_REVISION();
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t fpb_comp;
+  uint32_t replace;
+  uint32_t comp;
+  uint32_t i;
+
+  if (revision == 0)
+    {
+      replace = (addr & 0x2) == 0 ? 1 : 2;
+      fpb_comp = (addr & ~0x3) | FPB_COMP0_ENABLE_MASK |
+                 (replace << FPB_COMP0_REPLACE_SHIFT);
+    }
+  else
+    {
+      fpb_comp = addr | FPB_COMP0_ENABLE_MASK;
+    }
+
+  for (i = 0; i < num; i++)
+    {
+      comp = getreg32(FPB_COMP0 + i * 4);
+
+      if (comp == fpb_comp) /* Already set */
+        {
+          return 0;
+        }
+      else if (comp & FPB_COMP0_ENABLE_MASK) /* Comparators is in use */
+        {
+          continue;
+        }
+      else /* Find a free comparators */
+        {
+          putreg32(fpb_comp, FPB_COMP0 + i * 4);
+          return 0;
+        }
+    }
+
+  return -ENOSPC;
+}
+
+/****************************************************************************
+ * Name: arm_breakpoint_remove
+ *
+ * Description:
+ *   Remove a breakpoint on addr.
+ *
+ * Input Parameters:
+ *  addr - The address to remove.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_breakpoint_remove(uintptr_t addr)
+{
+  uint32_t revision = ARM_FPB_REVISION();
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t fpb_comp;
+  uint32_t replace;
+  uint32_t i;
+
+  if (revision == 0)
+    {
+      replace = (addr & 0x2) == 0 ? 1 : 2;
+      fpb_comp = (addr & ~0x3) | FPB_COMP0_ENABLE_MASK |
+                 (replace << FPB_COMP0_REPLACE_SHIFT);
+    }
+  else
+    {
+      fpb_comp = addr | FPB_COMP0_ENABLE_MASK;
+    }
+
+  for (i = 0; i < num; i++)
+    {
+      if (fpb_comp == getreg32(FPB_COMP0 + i * 4))
+        {
+          putreg32(0, FPB_COMP0 + i * 4);
+          return 0;
+        }
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: arm_breakpoint_match
+ *
+ * Description:
+ *   This function will be called when breakpoint match.
+ *
+ ****************************************************************************/
+
+static void arm_breakpoint_match(uint32_t pc)
+{
+  uint32_t i;
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].type == DEBUGPOINT_BREAKPOINT &&
+          g_arm_debug[i].addr == (void *)pc &&
+          g_arm_debug[i].callback)

Review Comment:
   Optional
   ```suggestion
             g_arm_debug[i].callback != NULL)
   ```



##########
libs/libc/gdbstub/lib_gdbstub.c:
##########
@@ -1366,13 +1365,260 @@ static int gdb_thread_context(FAR struct gdb_state_s 
*state)
  *   0  if successful.
  *   Negative value on error.
  *
+ * Note : Rsponse Format: T AA n1:r1;n2:r2;...
+ *        The program received signal number AA
+ *        n is thread id in current.
+ *        r is stop reason.
+ *
  ****************************************************************************/
 
-static int gdb_send_stop(FAR struct gdb_state_s *state)
+static int gdb_send_stop(FAR struct gdb_state_s *state, int stopreason,
+                         FAR void *stopaddr)
 {
-  return gdb_send_signal_packet(state, 0x00);
+  int ret;
+
+  state->pid = _SCHED_GETTID();
+retry:
+  switch (stopreason)
+    {
+      case GDBSTUB_STOPREASON_WATCHPOINT_RO:
+        ret = sprintf(state->pkt_buf, "T05thread:%x;rwatch:%" PRIxPTR ";",
+                      state->pid + 1, (uintptr_t)stopaddr);
+        break;
+      case GDBSTUB_STOPREASON_WATCHPOINT_WO:
+        ret = sprintf(state->pkt_buf, "T05thread:%x;awatch:%" PRIxPTR ";",
+                      state->pid + 1, (uintptr_t)stopaddr);
+        break;
+      case GDBSTUB_STOPREASON_WATCHPOINT_RW:
+        ret = sprintf(state->pkt_buf, "T05thread:%x;watch:%" PRIxPTR ";",
+                      state->pid + 1, (uintptr_t)stopaddr);
+        break;
+      case GDBSTUB_STOPREASON_BREAKPOINT:
+        ret = sprintf(state->pkt_buf, "T05thread:%x;hwbreak:;",
+                      state->pid + 1);
+        break;
+      case GDBSTUB_STOPREASON_STEPPOINT:
+        if (state->last_stopreason == GDBSTUB_STOPREASON_WATCHPOINT_RW ||
+            state->last_stopreason == GDBSTUB_STOPREASON_WATCHPOINT_WO)
+          {
+            stopreason = state->last_stopreason;
+            stopaddr = state->last_stopaddr;
+            goto retry;
+          }
+
+      case GDBSTUB_STOPREASON_CTRLC:
+      default:
+        ret = sprintf(state->pkt_buf, "T05thread:%d;", state->pid + 1);
+    }
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  state->pkt_len = ret;
+  return gdb_send_packet(state);
 }
 
+#ifdef CONFIG_ARCH_HAVE_DEBUG
+
+/****************************************************************************
+ * Name: gdbstub_debugpoint_callback
+ *
+ * Description:
+ *  The debugpoint callback is used by GDB to request.
+ *
+ ****************************************************************************/
+
+static void gdbstub_debugpoint_callback(int type, FAR void *addr,
+                                        size_t size, FAR void *arg)
+{
+  int stopreason;
+
+  switch (type)
+    {
+      case DEBUGPOINT_BREAKPOINT:
+        stopreason = GDBSTUB_STOPREASON_BREAKPOINT;
+        break;
+      case DEBUGPOINT_WATCHPOINT_RO:
+        stopreason = GDBSTUB_STOPREASON_WATCHPOINT_RO;
+        break;
+      case DEBUGPOINT_WATCHPOINT_WO:
+        stopreason = GDBSTUB_STOPREASON_WATCHPOINT_WO;
+        break;
+      case DEBUGPOINT_WATCHPOINT_RW:
+        stopreason = GDBSTUB_STOPREASON_WATCHPOINT_RW;
+        break;
+      case DEBUGPOINT_STEPPOINT:
+        stopreason = GDBSTUB_STOPREASON_STEPPOINT;
+        up_debugpoint_remove(DEBUGPOINT_STEPPOINT, NULL, 0);
+        break;
+      default:
+        return;
+    }
+
+  gdb_process(arg, stopreason, addr);
+}
+
+/****************************************************************************
+ * Name: gdb_debugpoint
+ *
+ * Description:
+ *   The debugpoint packet is used by GDB to request information from
+ *
+ * Input Parameters:
+ *   state  - The pointer to the GDB state structure.
+ *   enable - Enable or disable debugpoint.
+ *
+ * Returned Value:
+ *   0  if successful.
+ *   Negative value on error.
+ *
+ * Note : Comand Format: Z/z type,addr,length
+ *        Rsponse Format: OK
+ *   Z is set breakpoint.
+ *   z is clear breakpoint.
+ *   type: 0 is software breakpoint.
+ *         1 is hardware breakpoint.
+ *         2 is write watchpoint.
+ *         3 is read watchpoint.
+ *         4 is read/write watchpoint.
+ *   length: is the length of watchpoint.
+ *           if is breakpoint, length is instruction type.
+ *
+ ****************************************************************************/
+
+static int gdb_debugpoint(FAR struct gdb_state_s *state, bool enable)
+{
+  uintptr_t type;
+  uintptr_t addr;
+  uintptr_t size;
+  int ret;
+
+  state->pkt_next += 1;
+  ret = gdb_expect_integer(state, &type);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = gdb_expect_seperator(state, ',');
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = gdb_expect_integer(state, &addr);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = gdb_expect_seperator(state, ',');
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = gdb_expect_integer(state, &size);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  switch (type)
+    {
+      case 0: /* just use hardware break */
+      case 1:
+        type = DEBUGPOINT_BREAKPOINT;
+        break;
+      case 2:
+          type = DEBUGPOINT_WATCHPOINT_WO;

Review Comment:
   ```suggestion
           type = DEBUGPOINT_WATCHPOINT_WO;
   ```



##########
libs/libc/gdbstub/lib_gdbstub.c:
##########
@@ -1366,13 +1365,260 @@ static int gdb_thread_context(FAR struct gdb_state_s 
*state)
  *   0  if successful.
  *   Negative value on error.
  *
+ * Note : Rsponse Format: T AA n1:r1;n2:r2;...
+ *        The program received signal number AA
+ *        n is thread id in current.
+ *        r is stop reason.
+ *
  ****************************************************************************/
 
-static int gdb_send_stop(FAR struct gdb_state_s *state)
+static int gdb_send_stop(FAR struct gdb_state_s *state, int stopreason,
+                         FAR void *stopaddr)
 {
-  return gdb_send_signal_packet(state, 0x00);
+  int ret;
+
+  state->pid = _SCHED_GETTID();
+retry:
+  switch (stopreason)
+    {
+      case GDBSTUB_STOPREASON_WATCHPOINT_RO:
+        ret = sprintf(state->pkt_buf, "T05thread:%x;rwatch:%" PRIxPTR ";",
+                      state->pid + 1, (uintptr_t)stopaddr);
+        break;
+      case GDBSTUB_STOPREASON_WATCHPOINT_WO:
+        ret = sprintf(state->pkt_buf, "T05thread:%x;awatch:%" PRIxPTR ";",
+                      state->pid + 1, (uintptr_t)stopaddr);
+        break;
+      case GDBSTUB_STOPREASON_WATCHPOINT_RW:
+        ret = sprintf(state->pkt_buf, "T05thread:%x;watch:%" PRIxPTR ";",
+                      state->pid + 1, (uintptr_t)stopaddr);
+        break;
+      case GDBSTUB_STOPREASON_BREAKPOINT:
+        ret = sprintf(state->pkt_buf, "T05thread:%x;hwbreak:;",
+                      state->pid + 1);
+        break;
+      case GDBSTUB_STOPREASON_STEPPOINT:
+        if (state->last_stopreason == GDBSTUB_STOPREASON_WATCHPOINT_RW ||
+            state->last_stopreason == GDBSTUB_STOPREASON_WATCHPOINT_WO)
+          {
+            stopreason = state->last_stopreason;
+            stopaddr = state->last_stopaddr;
+            goto retry;
+          }
+
+      case GDBSTUB_STOPREASON_CTRLC:
+      default:
+        ret = sprintf(state->pkt_buf, "T05thread:%d;", state->pid + 1);
+    }
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  state->pkt_len = ret;
+  return gdb_send_packet(state);
 }
 
+#ifdef CONFIG_ARCH_HAVE_DEBUG
+
+/****************************************************************************
+ * Name: gdbstub_debugpoint_callback
+ *
+ * Description:
+ *  The debugpoint callback is used by GDB to request.
+ *
+ ****************************************************************************/
+
+static void gdbstub_debugpoint_callback(int type, FAR void *addr,
+                                        size_t size, FAR void *arg)
+{
+  int stopreason;
+
+  switch (type)
+    {
+      case DEBUGPOINT_BREAKPOINT:
+        stopreason = GDBSTUB_STOPREASON_BREAKPOINT;
+        break;
+      case DEBUGPOINT_WATCHPOINT_RO:
+        stopreason = GDBSTUB_STOPREASON_WATCHPOINT_RO;
+        break;
+      case DEBUGPOINT_WATCHPOINT_WO:
+        stopreason = GDBSTUB_STOPREASON_WATCHPOINT_WO;
+        break;
+      case DEBUGPOINT_WATCHPOINT_RW:
+        stopreason = GDBSTUB_STOPREASON_WATCHPOINT_RW;
+        break;
+      case DEBUGPOINT_STEPPOINT:
+        stopreason = GDBSTUB_STOPREASON_STEPPOINT;
+        up_debugpoint_remove(DEBUGPOINT_STEPPOINT, NULL, 0);
+        break;
+      default:
+        return;
+    }
+
+  gdb_process(arg, stopreason, addr);
+}
+
+/****************************************************************************
+ * Name: gdb_debugpoint
+ *
+ * Description:
+ *   The debugpoint packet is used by GDB to request information from
+ *
+ * Input Parameters:
+ *   state  - The pointer to the GDB state structure.
+ *   enable - Enable or disable debugpoint.
+ *
+ * Returned Value:
+ *   0  if successful.
+ *   Negative value on error.
+ *
+ * Note : Comand Format: Z/z type,addr,length
+ *        Rsponse Format: OK
+ *   Z is set breakpoint.
+ *   z is clear breakpoint.
+ *   type: 0 is software breakpoint.
+ *         1 is hardware breakpoint.
+ *         2 is write watchpoint.
+ *         3 is read watchpoint.
+ *         4 is read/write watchpoint.
+ *   length: is the length of watchpoint.
+ *           if is breakpoint, length is instruction type.
+ *
+ ****************************************************************************/
+
+static int gdb_debugpoint(FAR struct gdb_state_s *state, bool enable)
+{
+  uintptr_t type;
+  uintptr_t addr;
+  uintptr_t size;
+  int ret;
+
+  state->pkt_next += 1;
+  ret = gdb_expect_integer(state, &type);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = gdb_expect_seperator(state, ',');
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = gdb_expect_integer(state, &addr);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = gdb_expect_seperator(state, ',');
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = gdb_expect_integer(state, &size);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  switch (type)
+    {
+      case 0: /* just use hardware break */
+      case 1:
+        type = DEBUGPOINT_BREAKPOINT;
+        break;
+      case 2:
+          type = DEBUGPOINT_WATCHPOINT_WO;
+        break;
+      case 3:
+          type = DEBUGPOINT_WATCHPOINT_RO;
+        break;
+      case 4:
+          type = DEBUGPOINT_WATCHPOINT_RW;

Review Comment:
   ```suggestion
           type = DEBUGPOINT_WATCHPOINT_RW;
   ```



##########
libs/libc/gdbstub/lib_gdbstub.c:
##########
@@ -1366,13 +1365,260 @@ static int gdb_thread_context(FAR struct gdb_state_s 
*state)
  *   0  if successful.
  *   Negative value on error.
  *
+ * Note : Rsponse Format: T AA n1:r1;n2:r2;...
+ *        The program received signal number AA
+ *        n is thread id in current.
+ *        r is stop reason.
+ *
  ****************************************************************************/
 
-static int gdb_send_stop(FAR struct gdb_state_s *state)
+static int gdb_send_stop(FAR struct gdb_state_s *state, int stopreason,
+                         FAR void *stopaddr)
 {
-  return gdb_send_signal_packet(state, 0x00);
+  int ret;
+
+  state->pid = _SCHED_GETTID();
+retry:
+  switch (stopreason)
+    {
+      case GDBSTUB_STOPREASON_WATCHPOINT_RO:
+        ret = sprintf(state->pkt_buf, "T05thread:%x;rwatch:%" PRIxPTR ";",
+                      state->pid + 1, (uintptr_t)stopaddr);
+        break;
+      case GDBSTUB_STOPREASON_WATCHPOINT_WO:
+        ret = sprintf(state->pkt_buf, "T05thread:%x;awatch:%" PRIxPTR ";",
+                      state->pid + 1, (uintptr_t)stopaddr);
+        break;
+      case GDBSTUB_STOPREASON_WATCHPOINT_RW:
+        ret = sprintf(state->pkt_buf, "T05thread:%x;watch:%" PRIxPTR ";",
+                      state->pid + 1, (uintptr_t)stopaddr);
+        break;
+      case GDBSTUB_STOPREASON_BREAKPOINT:
+        ret = sprintf(state->pkt_buf, "T05thread:%x;hwbreak:;",
+                      state->pid + 1);
+        break;
+      case GDBSTUB_STOPREASON_STEPPOINT:
+        if (state->last_stopreason == GDBSTUB_STOPREASON_WATCHPOINT_RW ||
+            state->last_stopreason == GDBSTUB_STOPREASON_WATCHPOINT_WO)
+          {
+            stopreason = state->last_stopreason;
+            stopaddr = state->last_stopaddr;
+            goto retry;
+          }
+
+      case GDBSTUB_STOPREASON_CTRLC:
+      default:
+        ret = sprintf(state->pkt_buf, "T05thread:%d;", state->pid + 1);
+    }
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  state->pkt_len = ret;
+  return gdb_send_packet(state);
 }
 
+#ifdef CONFIG_ARCH_HAVE_DEBUG
+
+/****************************************************************************
+ * Name: gdbstub_debugpoint_callback
+ *
+ * Description:
+ *  The debugpoint callback is used by GDB to request.
+ *
+ ****************************************************************************/
+
+static void gdbstub_debugpoint_callback(int type, FAR void *addr,
+                                        size_t size, FAR void *arg)
+{
+  int stopreason;
+
+  switch (type)
+    {
+      case DEBUGPOINT_BREAKPOINT:
+        stopreason = GDBSTUB_STOPREASON_BREAKPOINT;
+        break;
+      case DEBUGPOINT_WATCHPOINT_RO:
+        stopreason = GDBSTUB_STOPREASON_WATCHPOINT_RO;
+        break;
+      case DEBUGPOINT_WATCHPOINT_WO:
+        stopreason = GDBSTUB_STOPREASON_WATCHPOINT_WO;
+        break;
+      case DEBUGPOINT_WATCHPOINT_RW:
+        stopreason = GDBSTUB_STOPREASON_WATCHPOINT_RW;
+        break;
+      case DEBUGPOINT_STEPPOINT:
+        stopreason = GDBSTUB_STOPREASON_STEPPOINT;
+        up_debugpoint_remove(DEBUGPOINT_STEPPOINT, NULL, 0);
+        break;
+      default:
+        return;
+    }
+
+  gdb_process(arg, stopreason, addr);
+}
+
+/****************************************************************************
+ * Name: gdb_debugpoint
+ *
+ * Description:
+ *   The debugpoint packet is used by GDB to request information from
+ *
+ * Input Parameters:
+ *   state  - The pointer to the GDB state structure.
+ *   enable - Enable or disable debugpoint.
+ *
+ * Returned Value:
+ *   0  if successful.
+ *   Negative value on error.
+ *
+ * Note : Comand Format: Z/z type,addr,length
+ *        Rsponse Format: OK
+ *   Z is set breakpoint.
+ *   z is clear breakpoint.
+ *   type: 0 is software breakpoint.
+ *         1 is hardware breakpoint.
+ *         2 is write watchpoint.
+ *         3 is read watchpoint.
+ *         4 is read/write watchpoint.
+ *   length: is the length of watchpoint.
+ *           if is breakpoint, length is instruction type.
+ *
+ ****************************************************************************/
+
+static int gdb_debugpoint(FAR struct gdb_state_s *state, bool enable)
+{
+  uintptr_t type;
+  uintptr_t addr;
+  uintptr_t size;
+  int ret;
+
+  state->pkt_next += 1;
+  ret = gdb_expect_integer(state, &type);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = gdb_expect_seperator(state, ',');
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = gdb_expect_integer(state, &addr);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = gdb_expect_seperator(state, ',');
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = gdb_expect_integer(state, &size);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  switch (type)
+    {
+      case 0: /* just use hardware break */
+      case 1:
+        type = DEBUGPOINT_BREAKPOINT;
+        break;
+      case 2:
+          type = DEBUGPOINT_WATCHPOINT_WO;
+        break;
+      case 3:
+          type = DEBUGPOINT_WATCHPOINT_RO;

Review Comment:
   ```suggestion
           type = DEBUGPOINT_WATCHPOINT_RO;
   ```



##########
arch/arm/src/armv7-m/arm_dbgmonitor.c:
##########
@@ -0,0 +1,673 @@
+/****************************************************************************
+ * arch/arm/src/armv7-m/arm_dbgmonitor.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/arch.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include "nvic.h"
+#include "fpb.h"
+#include "dwt.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* 4 watchpoint, 4 breakpoint, 1 single step */
+
+#define ARM_DEBUG_MAX (4 + 4 + 1)
+
+#define ARM_FPB_NUM() \
+        (((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE2_MASK) >> \
+          FPB_CTRL_NUM_CODE2_SHIFT << FPB_CTRL_NUM_CODE1_SHIFT) | \
+         ((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE1_MASK) >> \
+          FPB_CTRL_NUM_CODE1_SHIFT))
+
+#define ARM_FPB_REVISION() \
+        ((getreg32(FPB_CTRL) & FPB_CTRL_REV_MASK) >> FPB_CTRL_REV_SHIFT)
+
+#define ARM_DWT_NUM() \
+        ((getreg32(DWT_CTRL) & DWT_CTRL_NUMCOMP_MASK) >> \
+         DWT_CTRL_NUMCOMP_SHIFT)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct arm_debug_s
+{
+  int type;
+  void *addr;
+  size_t size;
+  debug_callback_t callback;
+  void *arg;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct arm_debug_s g_arm_debug[ARM_DEBUG_MAX];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_fpb_init
+ ****************************************************************************/
+
+static void arm_fpb_init(void)
+{
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, FPB_COMP0 + i * 4);
+    }
+
+  modifyreg32(FPB_CTRL, 0, FPB_CTRL_ENABLE_MASK | FPB_CTRL_KEY_MASK);
+}
+
+/****************************************************************************
+ * Name: arm_dwt_init
+ ****************************************************************************/
+
+static void arm_dwt_init(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+    }
+}
+
+/****************************************************************************
+ * Name: up_watchpoint_add
+ *
+ * Description:
+ *   Add a watchpoint on the address.
+ *
+ * Input Parameters:
+ *  type - The type of the watchpoint
+ *  addr - The address to be watched
+ *  size - The size of the address to be watched
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ * Notes:
+ *  The size of the watchpoint is determined by the hardware.
+ *  armv7-m supports only support 4 bytes.
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_add(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = 0;
+
+      if (getreg32(DWT_COMP0 + 16 * i) == 0)
+        {
+          switch (type)
+            {
+              case DEBUGPOINT_WATCHPOINT_RO:
+                fun |= DWT_FUNCTION_WATCHPOINT_RO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_WO:
+                fun |= DWT_FUNCTION_WATCHPOINT_WO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_RW:
+                fun |= DWT_FUNCTION_WATCHPOINT_RW;
+                break;
+              default:
+                return -EINVAL;
+            }
+
+          putreg32(fun, DWT_FUNCTION0 + 16 * i);
+          putreg32(addr, DWT_COMP0 + 16 * i);
+          putreg32(0, DWT_MASK0 + 16 * i);
+          return 0;
+        }
+    }
+
+  return -ENOSPC;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_remove
+ *
+ * Description:
+ *   Remove a watchpoint on the address.
+ *
+ * Input Parameters:
+ *   type - The type of the watchpoint.
+ *   addr - The address to be watched.
+ *   size - The size of the address to be watched.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_remove(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun_type = (getreg32(DWT_FUNCTION0 + 16 * i) &
+                          DWT_FUNCTION_FUNCTION_MASK) >>
+                          DWT_FUNCTION_FUNCTION_SHIFT;
+
+      switch (fun_type)
+        {
+          case DWT_FUNCTION_WATCHPOINT_RO:
+            if (type == DEBUGPOINT_WATCHPOINT_RO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_WO:
+            if (type == DEBUGPOINT_WATCHPOINT_WO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_RW:
+            if (type == DEBUGPOINT_WATCHPOINT_RW)
+              {
+                break;
+              }
+
+            continue;
+
+          default:
+            continue;
+        }
+
+      if (getreg32(DWT_COMP0 + 16 * i) != addr)
+        {
+          continue;
+        }
+
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      return 0;
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_match
+ *
+ * Description:
+ *   This function will be called when watchpoint match.
+ *
+ ****************************************************************************/
+
+static void arm_watchpoint_match(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t addr = 0;
+  uint32_t i;
+  int type = 0;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = getreg32(DWT_FUNCTION0 + 16 * i);
+      if (fun & DWT_FUNCTION_MATCHED_MASK)
+        {
+          uint32_t fun_type = (fun & DWT_FUNCTION_FUNCTION_MASK) >>
+                              DWT_FUNCTION_FUNCTION_SHIFT;
+
+          addr = getreg32(DWT_COMP0 + 16 * i);
+          switch (fun_type)
+            {
+              case DWT_FUNCTION_WATCHPOINT_RO:
+                  type = DEBUGPOINT_WATCHPOINT_RO;
+                  break;
+              case DWT_FUNCTION_WATCHPOINT_WO:
+                  type = DEBUGPOINT_WATCHPOINT_WO;
+                  break;
+              case DWT_FUNCTION_WATCHPOINT_RW:
+                  type = DEBUGPOINT_WATCHPOINT_RW;
+                  break;
+
+              default:
+                continue;
+            }
+        }
+    }
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].addr == (void *)addr &&
+          g_arm_debug[i].type == type && g_arm_debug[i].callback)
+        {
+          g_arm_debug[i].callback(g_arm_debug[i].type,
+                                  g_arm_debug[i].addr,
+                                  g_arm_debug[i].size,
+                                  g_arm_debug[i].arg);
+          break;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: arm_breakpoint_add
+ *
+ * Description:
+ *   Add a breakpoint on addr.
+ *
+ * Input Parameters:
+ *  addr - The address to break.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ * Notes:
+ *  1. If breakpoint is already set, it will do nothing.
+ *  2. If all comparators are in use, it will return -1.
+ *  3. When the breakpoint trigger, if enable monitor exception already ,
+ *     will cause a debug monitor exception, otherwise will cause
+ *     a hard fault.
+ *
+ ****************************************************************************/
+
+static int arm_breakpoint_add(uintptr_t addr)
+{
+  uint32_t revision = ARM_FPB_REVISION();
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t fpb_comp;
+  uint32_t replace;
+  uint32_t comp;
+  uint32_t i;
+
+  if (revision == 0)
+    {
+      replace = (addr & 0x2) == 0 ? 1 : 2;
+      fpb_comp = (addr & ~0x3) | FPB_COMP0_ENABLE_MASK |
+                 (replace << FPB_COMP0_REPLACE_SHIFT);
+    }
+  else
+    {
+      fpb_comp = addr | FPB_COMP0_ENABLE_MASK;
+    }
+
+  for (i = 0; i < num; i++)
+    {
+      comp = getreg32(FPB_COMP0 + i * 4);
+
+      if (comp == fpb_comp) /* Already set */
+        {
+          return 0;
+        }
+      else if (comp & FPB_COMP0_ENABLE_MASK) /* Comparators is in use */
+        {
+          continue;
+        }
+      else /* Find a free comparators */
+        {
+          putreg32(fpb_comp, FPB_COMP0 + i * 4);
+          return 0;
+        }
+    }
+
+  return -ENOSPC;
+}
+
+/****************************************************************************
+ * Name: arm_breakpoint_remove
+ *
+ * Description:
+ *   Remove a breakpoint on addr.
+ *
+ * Input Parameters:
+ *  addr - The address to remove.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_breakpoint_remove(uintptr_t addr)
+{
+  uint32_t revision = ARM_FPB_REVISION();
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t fpb_comp;
+  uint32_t replace;
+  uint32_t i;
+
+  if (revision == 0)
+    {
+      replace = (addr & 0x2) == 0 ? 1 : 2;
+      fpb_comp = (addr & ~0x3) | FPB_COMP0_ENABLE_MASK |
+                 (replace << FPB_COMP0_REPLACE_SHIFT);
+    }
+  else
+    {
+      fpb_comp = addr | FPB_COMP0_ENABLE_MASK;
+    }
+
+  for (i = 0; i < num; i++)
+    {
+      if (fpb_comp == getreg32(FPB_COMP0 + i * 4))
+        {
+          putreg32(0, FPB_COMP0 + i * 4);
+          return 0;
+        }
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: arm_breakpoint_match
+ *
+ * Description:
+ *   This function will be called when breakpoint match.
+ *
+ ****************************************************************************/
+
+static void arm_breakpoint_match(uint32_t pc)
+{
+  uint32_t i;
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].type == DEBUGPOINT_BREAKPOINT &&
+          g_arm_debug[i].addr == (void *)pc &&
+          g_arm_debug[i].callback)
+        {
+          g_arm_debug[i].callback(g_arm_debug[i].type,
+                                  g_arm_debug[i].addr,
+                                  g_arm_debug[i].size,
+                                  g_arm_debug[i].arg);
+          break;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: arm_steppoint
+ *
+ * Description:
+ *   Enable/disable single step.
+ *
+ * Input Parameters:
+ *  enable - True: enable single step; False: disable single step.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_steppoint(bool enable)
+{
+  if (enable)
+    {
+      modifyreg32(NVIC_DEMCR, 0, NVIC_DEMCR_MONSTEP);
+    }
+  else
+    {
+      modifyreg32(NVIC_DEMCR, NVIC_DEMCR_MONSTEP, 0);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: arm_steppoint_match
+ *
+ * Description:
+ *   This function will be called when single step match.
+ *
+ ****************************************************************************/
+
+static void arm_steppoint_match(void)
+{
+  uint32_t i;
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].type == DEBUGPOINT_STEPPOINT &&
+          g_arm_debug[i].callback)
+        {
+          g_arm_debug[i].callback(g_arm_debug[i].type,
+                                  g_arm_debug[i].addr,
+                                  g_arm_debug[i].size,
+                                  g_arm_debug[i].arg);
+          break;
+        }
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_debugpoint_add
+ *
+ * Description:
+ *   Add a debugpoint.
+ *
+ * Input Parameters:
+ *   type     - The debugpoint type. optional value:
+ *              DEBUGPOINT_WATCHPOINT_RO - Read only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_WO - Write only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_RW - Read and write watchpoint.
+ *              DEBUGPOINT_BREAKPOINT    - Breakpoint.
+ *              DEBUGPOINT_STEPPOINT     - Single step.
+ *   addr     - The address to be debugged.
+ *   size     - The watchpoint size. only for watchpoint.
+ *   callback - The callback function when debugpoint triggered.
+ *              if NULL, the debugpoint will be removed.
+ *   arg      - The argument of callback function.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+int up_debugpoint_add(int type, void *addr, size_t size,
+                      debug_callback_t callback, void *arg)
+{
+  int ret = -EINVAL;
+  uint32_t i;
+
+  if (type == DEBUGPOINT_BREAKPOINT)
+    {
+      ret = arm_breakpoint_add((uintptr_t)addr);
+
+      /* Thumb mode breakpoint address must be word-aligned */
+
+      addr = (void *)((uintptr_t)addr & ~0x1);
+    }
+  else if (type == DEBUGPOINT_WATCHPOINT_RO ||
+           type == DEBUGPOINT_WATCHPOINT_WO ||
+           type == DEBUGPOINT_WATCHPOINT_RW)
+    {
+      ret = arm_watchpoint_add(type, (uintptr_t)addr, size);
+    }
+  else if (type == DEBUGPOINT_STEPPOINT)
+    {
+      ret = arm_steppoint(true);
+    }
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].type == DEBUGPOINT_NONE)
+        {
+          g_arm_debug[i].type = type;
+          g_arm_debug[i].addr = addr;
+          g_arm_debug[i].size = size;
+          g_arm_debug[i].callback = callback;
+          g_arm_debug[i].arg = arg;
+          break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: up_debugpoint_remove
+ *
+ * Description:
+ *   Remove a debugpoint.
+ *
+ * Input Parameters:
+ *   type     - The debugpoint type. optional value:
+ *              DEBUGPOINT_WATCHPOINT_RO - Read only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_WO - Write only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_RW - Read and write watchpoint.
+ *              DEBUGPOINT_BREAKPOINT    - Breakpoint.
+ *              DEBUGPOINT_STEPPOINT     - Single step.
+ *   addr     - The address to be debugged.
+ *   size     - The watchpoint size. only for watchpoint.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+int up_debugpoint_remove(int type, void *addr, size_t size)
+{
+  int ret = -EINVAL;
+  uint32_t i;
+
+  if (type == DEBUGPOINT_BREAKPOINT)
+    {
+      ret = arm_breakpoint_remove((uintptr_t)addr);
+
+      /* Thumb mode breakpoint address must be word-aligned */
+
+      addr = (void *)((uintptr_t)addr & ~0x1);
+    }
+  else if (type == DEBUGPOINT_WATCHPOINT_RO ||
+           type == DEBUGPOINT_WATCHPOINT_WO ||
+           type == DEBUGPOINT_WATCHPOINT_RW)
+    {
+      ret = arm_watchpoint_remove(type, (uintptr_t)addr, size);
+    }
+  else if (type == DEBUGPOINT_STEPPOINT)
+    {
+      ret = arm_steppoint(false);
+    }
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].type == type &&
+          g_arm_debug[i].size == size &&
+          g_arm_debug[i].addr == addr)
+        {
+          g_arm_debug[i].type = DEBUGPOINT_NONE;
+          break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: arm_enable_dbgmonitor
+ *
+ * Description:
+ *   This function enables the debug monitor exception.
+ *
+ ****************************************************************************/
+
+int arm_enable_dbgmonitor(void)
+{
+  arm_fpb_init();
+  arm_dwt_init();
+  modifyreg32(NVIC_DEMCR, 0, NVIC_DEMCR_MONEN | NVIC_DEMCR_TRCENA);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: arm_dbgmonitor
+ *
+ * Description:
+ *   This is Debug Monitor exception handler.  This function is entered when
+ *   the processor enters debug mode.  The debug monitor handler will handle
+ *   debug events, and resume execution.
+ *
+ ****************************************************************************/
+
+int arm_dbgmonitor(int irq, void *context, void *arg)
+{
+  uint32_t dfsr = getreg32(NVIC_DFAULTS);
+  uint32_t *regs = (uint32_t *)context;
+
+  if (dfsr & NVIC_DFAULTS_HALTED)
+    {
+      arm_steppoint_match();
+    }
+
+  if (dfsr & NVIC_DFAULTS_BKPT)

Review Comment:
   same



##########
arch/arm/src/armv7-m/arm_dbgmonitor.c:
##########
@@ -0,0 +1,673 @@
+/****************************************************************************
+ * arch/arm/src/armv7-m/arm_dbgmonitor.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/arch.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include "nvic.h"
+#include "fpb.h"
+#include "dwt.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* 4 watchpoint, 4 breakpoint, 1 single step */
+
+#define ARM_DEBUG_MAX (4 + 4 + 1)
+
+#define ARM_FPB_NUM() \
+        (((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE2_MASK) >> \
+          FPB_CTRL_NUM_CODE2_SHIFT << FPB_CTRL_NUM_CODE1_SHIFT) | \
+         ((getreg32(FPB_CTRL) & FPB_CTRL_NUM_CODE1_MASK) >> \
+          FPB_CTRL_NUM_CODE1_SHIFT))
+
+#define ARM_FPB_REVISION() \
+        ((getreg32(FPB_CTRL) & FPB_CTRL_REV_MASK) >> FPB_CTRL_REV_SHIFT)
+
+#define ARM_DWT_NUM() \
+        ((getreg32(DWT_CTRL) & DWT_CTRL_NUMCOMP_MASK) >> \
+         DWT_CTRL_NUMCOMP_SHIFT)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct arm_debug_s
+{
+  int type;
+  void *addr;
+  size_t size;
+  debug_callback_t callback;
+  void *arg;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct arm_debug_s g_arm_debug[ARM_DEBUG_MAX];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_fpb_init
+ ****************************************************************************/
+
+static void arm_fpb_init(void)
+{
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, FPB_COMP0 + i * 4);
+    }
+
+  modifyreg32(FPB_CTRL, 0, FPB_CTRL_ENABLE_MASK | FPB_CTRL_KEY_MASK);
+}
+
+/****************************************************************************
+ * Name: arm_dwt_init
+ ****************************************************************************/
+
+static void arm_dwt_init(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+    }
+}
+
+/****************************************************************************
+ * Name: up_watchpoint_add
+ *
+ * Description:
+ *   Add a watchpoint on the address.
+ *
+ * Input Parameters:
+ *  type - The type of the watchpoint
+ *  addr - The address to be watched
+ *  size - The size of the address to be watched
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ * Notes:
+ *  The size of the watchpoint is determined by the hardware.
+ *  armv7-m supports only support 4 bytes.
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_add(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = 0;
+
+      if (getreg32(DWT_COMP0 + 16 * i) == 0)
+        {
+          switch (type)
+            {
+              case DEBUGPOINT_WATCHPOINT_RO:
+                fun |= DWT_FUNCTION_WATCHPOINT_RO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_WO:
+                fun |= DWT_FUNCTION_WATCHPOINT_WO;
+                break;
+              case DEBUGPOINT_WATCHPOINT_RW:
+                fun |= DWT_FUNCTION_WATCHPOINT_RW;
+                break;
+              default:
+                return -EINVAL;
+            }
+
+          putreg32(fun, DWT_FUNCTION0 + 16 * i);
+          putreg32(addr, DWT_COMP0 + 16 * i);
+          putreg32(0, DWT_MASK0 + 16 * i);
+          return 0;
+        }
+    }
+
+  return -ENOSPC;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_remove
+ *
+ * Description:
+ *   Remove a watchpoint on the address.
+ *
+ * Input Parameters:
+ *   type - The type of the watchpoint.
+ *   addr - The address to be watched.
+ *   size - The size of the address to be watched.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_watchpoint_remove(int type, uint32_t addr, size_t size)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t i;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun_type = (getreg32(DWT_FUNCTION0 + 16 * i) &
+                          DWT_FUNCTION_FUNCTION_MASK) >>
+                          DWT_FUNCTION_FUNCTION_SHIFT;
+
+      switch (fun_type)
+        {
+          case DWT_FUNCTION_WATCHPOINT_RO:
+            if (type == DEBUGPOINT_WATCHPOINT_RO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_WO:
+            if (type == DEBUGPOINT_WATCHPOINT_WO)
+              {
+                break;
+              }
+
+            continue;
+          case DWT_FUNCTION_WATCHPOINT_RW:
+            if (type == DEBUGPOINT_WATCHPOINT_RW)
+              {
+                break;
+              }
+
+            continue;
+
+          default:
+            continue;
+        }
+
+      if (getreg32(DWT_COMP0 + 16 * i) != addr)
+        {
+          continue;
+        }
+
+      putreg32(0, DWT_COMP0 + 16 * i);
+      putreg32(0, DWT_FUNCTION0 + 16 * i);
+      putreg32(0, DWT_MASK0 + 16 * i);
+      return 0;
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: arm_watchpoint_match
+ *
+ * Description:
+ *   This function will be called when watchpoint match.
+ *
+ ****************************************************************************/
+
+static void arm_watchpoint_match(void)
+{
+  uint32_t num = ARM_DWT_NUM();
+  uint32_t addr = 0;
+  uint32_t i;
+  int type = 0;
+
+  for (i = 0; i < num; i++)
+    {
+      uint32_t fun = getreg32(DWT_FUNCTION0 + 16 * i);
+      if (fun & DWT_FUNCTION_MATCHED_MASK)
+        {
+          uint32_t fun_type = (fun & DWT_FUNCTION_FUNCTION_MASK) >>
+                              DWT_FUNCTION_FUNCTION_SHIFT;
+
+          addr = getreg32(DWT_COMP0 + 16 * i);
+          switch (fun_type)
+            {
+              case DWT_FUNCTION_WATCHPOINT_RO:
+                  type = DEBUGPOINT_WATCHPOINT_RO;
+                  break;
+              case DWT_FUNCTION_WATCHPOINT_WO:
+                  type = DEBUGPOINT_WATCHPOINT_WO;
+                  break;
+              case DWT_FUNCTION_WATCHPOINT_RW:
+                  type = DEBUGPOINT_WATCHPOINT_RW;
+                  break;
+
+              default:
+                continue;
+            }
+        }
+    }
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].addr == (void *)addr &&
+          g_arm_debug[i].type == type && g_arm_debug[i].callback)
+        {
+          g_arm_debug[i].callback(g_arm_debug[i].type,
+                                  g_arm_debug[i].addr,
+                                  g_arm_debug[i].size,
+                                  g_arm_debug[i].arg);
+          break;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: arm_breakpoint_add
+ *
+ * Description:
+ *   Add a breakpoint on addr.
+ *
+ * Input Parameters:
+ *  addr - The address to break.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ * Notes:
+ *  1. If breakpoint is already set, it will do nothing.
+ *  2. If all comparators are in use, it will return -1.
+ *  3. When the breakpoint trigger, if enable monitor exception already ,
+ *     will cause a debug monitor exception, otherwise will cause
+ *     a hard fault.
+ *
+ ****************************************************************************/
+
+static int arm_breakpoint_add(uintptr_t addr)
+{
+  uint32_t revision = ARM_FPB_REVISION();
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t fpb_comp;
+  uint32_t replace;
+  uint32_t comp;
+  uint32_t i;
+
+  if (revision == 0)
+    {
+      replace = (addr & 0x2) == 0 ? 1 : 2;
+      fpb_comp = (addr & ~0x3) | FPB_COMP0_ENABLE_MASK |
+                 (replace << FPB_COMP0_REPLACE_SHIFT);
+    }
+  else
+    {
+      fpb_comp = addr | FPB_COMP0_ENABLE_MASK;
+    }
+
+  for (i = 0; i < num; i++)
+    {
+      comp = getreg32(FPB_COMP0 + i * 4);
+
+      if (comp == fpb_comp) /* Already set */
+        {
+          return 0;
+        }
+      else if (comp & FPB_COMP0_ENABLE_MASK) /* Comparators is in use */
+        {
+          continue;
+        }
+      else /* Find a free comparators */
+        {
+          putreg32(fpb_comp, FPB_COMP0 + i * 4);
+          return 0;
+        }
+    }
+
+  return -ENOSPC;
+}
+
+/****************************************************************************
+ * Name: arm_breakpoint_remove
+ *
+ * Description:
+ *   Remove a breakpoint on addr.
+ *
+ * Input Parameters:
+ *  addr - The address to remove.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_breakpoint_remove(uintptr_t addr)
+{
+  uint32_t revision = ARM_FPB_REVISION();
+  uint32_t num = ARM_FPB_NUM();
+  uint32_t fpb_comp;
+  uint32_t replace;
+  uint32_t i;
+
+  if (revision == 0)
+    {
+      replace = (addr & 0x2) == 0 ? 1 : 2;
+      fpb_comp = (addr & ~0x3) | FPB_COMP0_ENABLE_MASK |
+                 (replace << FPB_COMP0_REPLACE_SHIFT);
+    }
+  else
+    {
+      fpb_comp = addr | FPB_COMP0_ENABLE_MASK;
+    }
+
+  for (i = 0; i < num; i++)
+    {
+      if (fpb_comp == getreg32(FPB_COMP0 + i * 4))
+        {
+          putreg32(0, FPB_COMP0 + i * 4);
+          return 0;
+        }
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: arm_breakpoint_match
+ *
+ * Description:
+ *   This function will be called when breakpoint match.
+ *
+ ****************************************************************************/
+
+static void arm_breakpoint_match(uint32_t pc)
+{
+  uint32_t i;
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].type == DEBUGPOINT_BREAKPOINT &&
+          g_arm_debug[i].addr == (void *)pc &&
+          g_arm_debug[i].callback)
+        {
+          g_arm_debug[i].callback(g_arm_debug[i].type,
+                                  g_arm_debug[i].addr,
+                                  g_arm_debug[i].size,
+                                  g_arm_debug[i].arg);
+          break;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: arm_steppoint
+ *
+ * Description:
+ *   Enable/disable single step.
+ *
+ * Input Parameters:
+ *  enable - True: enable single step; False: disable single step.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int arm_steppoint(bool enable)
+{
+  if (enable)
+    {
+      modifyreg32(NVIC_DEMCR, 0, NVIC_DEMCR_MONSTEP);
+    }
+  else
+    {
+      modifyreg32(NVIC_DEMCR, NVIC_DEMCR_MONSTEP, 0);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: arm_steppoint_match
+ *
+ * Description:
+ *   This function will be called when single step match.
+ *
+ ****************************************************************************/
+
+static void arm_steppoint_match(void)
+{
+  uint32_t i;
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].type == DEBUGPOINT_STEPPOINT &&
+          g_arm_debug[i].callback)
+        {
+          g_arm_debug[i].callback(g_arm_debug[i].type,
+                                  g_arm_debug[i].addr,
+                                  g_arm_debug[i].size,
+                                  g_arm_debug[i].arg);
+          break;
+        }
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_debugpoint_add
+ *
+ * Description:
+ *   Add a debugpoint.
+ *
+ * Input Parameters:
+ *   type     - The debugpoint type. optional value:
+ *              DEBUGPOINT_WATCHPOINT_RO - Read only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_WO - Write only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_RW - Read and write watchpoint.
+ *              DEBUGPOINT_BREAKPOINT    - Breakpoint.
+ *              DEBUGPOINT_STEPPOINT     - Single step.
+ *   addr     - The address to be debugged.
+ *   size     - The watchpoint size. only for watchpoint.
+ *   callback - The callback function when debugpoint triggered.
+ *              if NULL, the debugpoint will be removed.
+ *   arg      - The argument of callback function.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+int up_debugpoint_add(int type, void *addr, size_t size,
+                      debug_callback_t callback, void *arg)
+{
+  int ret = -EINVAL;
+  uint32_t i;
+
+  if (type == DEBUGPOINT_BREAKPOINT)
+    {
+      ret = arm_breakpoint_add((uintptr_t)addr);
+
+      /* Thumb mode breakpoint address must be word-aligned */
+
+      addr = (void *)((uintptr_t)addr & ~0x1);
+    }
+  else if (type == DEBUGPOINT_WATCHPOINT_RO ||
+           type == DEBUGPOINT_WATCHPOINT_WO ||
+           type == DEBUGPOINT_WATCHPOINT_RW)
+    {
+      ret = arm_watchpoint_add(type, (uintptr_t)addr, size);
+    }
+  else if (type == DEBUGPOINT_STEPPOINT)
+    {
+      ret = arm_steppoint(true);
+    }
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].type == DEBUGPOINT_NONE)
+        {
+          g_arm_debug[i].type = type;
+          g_arm_debug[i].addr = addr;
+          g_arm_debug[i].size = size;
+          g_arm_debug[i].callback = callback;
+          g_arm_debug[i].arg = arg;
+          break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: up_debugpoint_remove
+ *
+ * Description:
+ *   Remove a debugpoint.
+ *
+ * Input Parameters:
+ *   type     - The debugpoint type. optional value:
+ *              DEBUGPOINT_WATCHPOINT_RO - Read only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_WO - Write only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_RW - Read and write watchpoint.
+ *              DEBUGPOINT_BREAKPOINT    - Breakpoint.
+ *              DEBUGPOINT_STEPPOINT     - Single step.
+ *   addr     - The address to be debugged.
+ *   size     - The watchpoint size. only for watchpoint.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+int up_debugpoint_remove(int type, void *addr, size_t size)
+{
+  int ret = -EINVAL;
+  uint32_t i;
+
+  if (type == DEBUGPOINT_BREAKPOINT)
+    {
+      ret = arm_breakpoint_remove((uintptr_t)addr);
+
+      /* Thumb mode breakpoint address must be word-aligned */
+
+      addr = (void *)((uintptr_t)addr & ~0x1);
+    }
+  else if (type == DEBUGPOINT_WATCHPOINT_RO ||
+           type == DEBUGPOINT_WATCHPOINT_WO ||
+           type == DEBUGPOINT_WATCHPOINT_RW)
+    {
+      ret = arm_watchpoint_remove(type, (uintptr_t)addr, size);
+    }
+  else if (type == DEBUGPOINT_STEPPOINT)
+    {
+      ret = arm_steppoint(false);
+    }
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  for (i = 0; i < ARM_DEBUG_MAX; i++)
+    {
+      if (g_arm_debug[i].type == type &&
+          g_arm_debug[i].size == size &&
+          g_arm_debug[i].addr == addr)
+        {
+          g_arm_debug[i].type = DEBUGPOINT_NONE;
+          break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: arm_enable_dbgmonitor
+ *
+ * Description:
+ *   This function enables the debug monitor exception.
+ *
+ ****************************************************************************/
+
+int arm_enable_dbgmonitor(void)
+{
+  arm_fpb_init();
+  arm_dwt_init();
+  modifyreg32(NVIC_DEMCR, 0, NVIC_DEMCR_MONEN | NVIC_DEMCR_TRCENA);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: arm_dbgmonitor
+ *
+ * Description:
+ *   This is Debug Monitor exception handler.  This function is entered when
+ *   the processor enters debug mode.  The debug monitor handler will handle
+ *   debug events, and resume execution.
+ *
+ ****************************************************************************/
+
+int arm_dbgmonitor(int irq, void *context, void *arg)
+{
+  uint32_t dfsr = getreg32(NVIC_DFAULTS);
+  uint32_t *regs = (uint32_t *)context;
+
+  if (dfsr & NVIC_DFAULTS_HALTED)

Review Comment:
   Optional: add `!= 0`



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to