You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by GitBox <gi...@apache.org> on 2022/10/09 04:39:02 UTC

[GitHub] [incubator-nuttx] anchao opened a new pull request, #7260: arm/backtrace: add support for EHABI(Exception Handling ABI) stack unwinder

anchao opened a new pull request, #7260:
URL: https://github.com/apache/incubator-nuttx/pull/7260

   ## Summary
   
   arm/backtrace: add support for EHABI(Exception Handling ABI) stack unwinder
   
   Reference:
   https://github.com/ARM-software/abi-aa/blob/main/ehabi32/ehabi32.rst https://github.com/ARM-software/abi-aa/releases/download/2022Q1/ehabi32.pdf
   
   Signed-off-by: chao an <an...@xiaomi.com>
   
   ## Impact
   
   N/A
   
   ## Testing
   
   lm3s6965-ek/qemu-flat
   
   ```
   $ qemu-system-arm -semihosting -M lm3s6965evb -device loader,file=nuttx.bin,addr=0x00000000 -netdev user,id=user0 -nic user,id=user0 -serial mon:stdio -nographic 
   ABCDF
   
   NuttShell (NSH) NuttX-10.4.0
   nsh> ps
     PID GROUP PRI POLICY   TYPE    NPX STATE    EVENT     SIGMASK   STACK   USED  FILLED COMMAND
       0     0   0 FIFO     Kthread N-- Ready              00000000 001000 000372  37.2%  Idle Task
       1     1 224 RR       Kthread --- Waiting  Semaphore 00000000 001992 000280  14.0%  hpwork 0x20000970
       2     2 100 RR       Task    --- Running            00000000 002000 001144  57.2%  nsh_main
   nsh> dumpstack 0
   [ 3] backtrace| 0: 0x00005f18 0x00002120
   nsh> dumpstack 1
   [ 7] backtrace| 1: 0x00006326 0x0000631c 0x00003010 0x00003038 0x00002a6a 0x0000286e
   nsh> dumpstack 2
   [11] backtrace| 2: 0x00006326 0x0000631c 0x00003010 0x00010f74 0x00010f82 0x0000a90c 0x00006fda 0x00007bfe
   [11] backtrace| 2: 0x00006ada 0x0000677c 0x00006732 0x00004b96 0x00002884
   nsh> dumpstack
   [15] backtrace|15: 0x00015c8a 0x0001242e 0x000141fc 0x00004b96 0x00002884
   nsh> 
   
   ```
   
   ```
   Thread 0 (Idle Task):
   $ arm-none-eabi-addr2line -e nuttx 0x00005f18 0x00002120
   nuttx/arch/arm/src/chip/common/tiva_idle.c:59
   nuttx/sched/init/nx_start.c:690 (discriminator 1)
   
   Thread 1 (hpwork):
   $ arm-none-eabi-addr2line -e nuttx 0x00006326 0x0000631c 0x00003010 0x00003038 0x00002a6a 0x0000286e
   nuttx/include/arch/syscall.h:186
   nuttx/arch/arm/src/common/arm_blocktask.c:136
   nuttx/sched/semaphore/sem_wait.c:155 (discriminator 2)
   nuttx/sched/semaphore/sem_wait.c:224 (discriminator 1)
   nuttx/sched/wqueue/kwork_thread.c:147
   nuttx/sched/task/task_start.c:129
   
   Thread 2 (nsh_main):
   $ arm-none-eabi-addr2line -e nuttx 0x00006326 0x0000631c 0x00003010 0x00010f74 0x00010f82 0x0000a90c 0x00006fda 0x00007bfe 0x00006ada 0x0000677c 0x00006732 0x00004b96 0x00002884
   nuttx/include/arch/syscall.h:186
   nuttx/arch/arm/src/common/arm_blocktask.c:136
   nuttx/sched/semaphore/sem_wait.c:155 (discriminator 2)
   nuttx/sched/sched/sched_waitpid.c:127
   nuttx/sched/sched/sched_waitpid.c:597
   apps/nshlib/nsh_builtin.c:160
   apps/nshlib/nsh_parse.c:530
   apps/nshlib/nsh_parse.c:2594
   apps/nshlib/nsh_session.c:217
   apps/nshlib/nsh_consolemain.c:106 (discriminator 2)
   apps/system/nsh/nsh_main.c:154
   nuttx/libs/libc/sched/task_startup.c:70 (discriminator 2)
   nuttx/sched/task/task_start.c:134
   
   Thread 15 (dumpstack self):
   $ arm-none-eabi-addr2line -e nuttx 0x00015c8a 0x0001242e 0x000141fc 0x00004b96 0x00002884
   arm_backtrace_unwind.c:?
   nuttx/libs/libc/sched/sched_dumpstack.c:69
   apps/system/dumpstack/dumpstack.c:65 (discriminator 1)
   nuttx/libs/libc/sched/task_startup.c:70 (discriminator 2)
   nuttx/sched/task/task_start.c:134
   
   ```


-- 
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-unsubscribe@nuttx.apache.org

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


[GitHub] [incubator-nuttx] xiaoxiang781216 commented on a diff in pull request #7260: arm/backtrace: add support for EHABI(Exception Handling ABI) stack unwinder

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 commented on code in PR #7260:
URL: https://github.com/apache/incubator-nuttx/pull/7260#discussion_r990736217


##########
arch/arm/src/common/Make.defs:
##########
@@ -64,15 +64,17 @@ ifeq ($(CONFIG_SCHED_THREAD_LOCAL),y)
 endif
 
 ifeq ($(CONFIG_SCHED_BACKTRACE),y)

Review Comment:
   remove, don't need check



##########
arch/arm/src/common/arm_backtrace_unwind.c:
##########
@@ -0,0 +1,680 @@
+/****************************************************************************
+ * arch/arm/src/common/arm_backtrace_unwind.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 <arch/elf.h>
+
+#include "sched/sched.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum regs
+{
+#ifdef CONFIG_ARM_THUMB
+  FP = 7,
+#else
+  FP = 11,
+#endif /* CONFIG_ARM_THUMB */
+  SP = 13,
+  LR = 14,
+  PC = 15
+};
+
+/****************************************************************************
+ * Private Data Types
+ ****************************************************************************/
+
+struct unwind_frame_s
+{
+  unsigned long fp;
+  unsigned long sp;
+  unsigned long lr;
+  unsigned long pc;
+
+  /* address of the LR value on the stack */
+
+  unsigned long *lr_addr;
+
+  /* highest value of sp allowed */
+
+  unsigned long stack_top;
+};
+
+struct unwind_ctrl_s
+{
+  unsigned long        vrs[16];   /* virtual register set */
+  const unsigned long *insn;      /* pointer to the current instructions word */
+  unsigned long        stack_top; /* highest value of sp allowed */
+  unsigned long       *lr_addr;   /* address of LR value on the stack */
+  int                  entries;   /* number of entries left to interpret */
+  int                  byte;      /* current byte number in the instructions word */
+
+  /* 1 : check for stack overflow for each register pop.
+   * 0 : save overhead if there is plenty of stack remaining.
+   */
+
+  int check_each_pop;
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Convert a prel31 symbol to an absolute address */
+
+#define prel31_to_addr(ptr)  \
+  ({  \
+  /* sign-extend to 32 bits */  \
+  long offset = (((long)*(ptr)) << 1) >> 1;  \
+  (unsigned long)(ptr) + offset;  \
+  })
+
+/****************************************************************************
+ * Name: search_index
+ *
+ * Description:
+ *  Binary search in the unwind index. The entries are
+ *  guaranteed to be sorted in ascending order by the linker.
+ *
+ *  start    = first entry
+ *  origin   = first entry with positive offset
+ *             (or stop if there is no such entry)
+ *  stop - 1 = last entry
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static const struct __EIT_entry *
+search_index(unsigned long addr, const struct __EIT_entry *start,
+             const struct __EIT_entry *origin,
+             const struct __EIT_entry *stop)
+{
+  unsigned long addr_prel31;
+
+  /* only search in the section with the matching sign. This way the
+   * prel31 numbers can be compared as unsigned longs.
+   */
+
+  if (addr < (unsigned long)start)
+    {
+      /* negative offsets: [start; origin) */
+
+      stop = origin;
+    }
+  else
+    {
+      /* positive offsets: [origin; stop) */
+
+      start = origin;
+    }
+
+  /* prel31 for address relavive to start */
+
+  addr_prel31 = (addr - (unsigned long)start) & 0x7fffffff;
+
+  while (start < stop - 1)
+    {
+      const struct __EIT_entry *mid = start + ((stop - start) >> 1);
+
+      /* As addr_prel31 is relative to start an offset is needed to
+       * make it relative to mid.
+       */
+
+      if (addr_prel31 -
+          ((unsigned long)mid - (unsigned long)start) < mid->fnoffset)
+        {
+          stop = mid;
+        }
+      else
+        {
+          /* keep addr_prel31 relative to start */
+
+          addr_prel31 -= ((unsigned long)mid - (unsigned long)start);
+          start = mid;
+        }
+    }
+
+  return (start->fnoffset <= addr_prel31) ? start : NULL;
+}
+
+nosanitize_address
+static const struct __EIT_entry *
+unwind_find_origin(const struct __EIT_entry *start,
+                   const struct __EIT_entry *stop)
+{
+  const struct __EIT_entry *mid;
+
+  while (start < stop)
+    {
+      mid = start + ((stop - start) >> 1);
+
+      if (mid->fnoffset >= 0x40000000)
+        {
+          /* negative offset */
+
+          start = mid + 1;
+        }
+      else
+        {
+          /* positive offset */
+
+          stop = mid;
+        }
+    }
+
+  return stop;
+}
+
+nosanitize_address
+static const struct __EIT_entry *unwind_find_entry(unsigned long addr)
+{
+  /* main unwind table */
+
+  return search_index(addr, __exidx_start,
+                      unwind_find_origin(__exidx_start, __exidx_end),
+                      __exidx_end);
+}
+
+nosanitize_address
+static unsigned long unwind_get_byte(struct unwind_ctrl_s *ctrl)
+{
+  unsigned long ret;
+
+  if (ctrl->entries <= 0)
+    {
+      return 0;
+    }
+
+  ret = (*ctrl->insn >> (ctrl->byte * 8)) & 0xff;
+
+  if (ctrl->byte == 0)
+    {
+      ctrl->insn++;
+      ctrl->entries--;
+      ctrl->byte = 3;
+    }
+  else
+    {
+      ctrl->byte--;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Before poping a register check whether it is feasible or not
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static int unwind_pop_register(struct unwind_ctrl_s *ctrl,
+                               unsigned long **vsp, unsigned int reg)
+{
+  if (ctrl->check_each_pop)
+    {
+      if (*vsp >= (unsigned long *)ctrl->stack_top)
+        {
+          return -1;
+        }
+    }
+
+  /* Use READ_ONCE_NOCHECK here to avoid this memory access
+   * from being tracked by KASAN.
+   */
+
+  ctrl->vrs[reg] = *(*vsp);
+  if (reg == LR)
+    {
+      ctrl->lr_addr = *vsp;
+    }
+
+  (*vsp)++;
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Helper functions to execute the instructions
+ *
+ ****************************************************************************/
+
+nosanitize_address static int
+unwind_exec_pop_subset_r4_to_r13(struct unwind_ctrl_s *ctrl,
+                                 unsigned long mask)
+{
+  unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+  int load_sp;
+  int reg = 4;
+
+  load_sp = mask & (1 << (13 - 4));
+  while (mask)
+    {
+      if ((mask & 1) && unwind_pop_register(ctrl, &vsp, reg))
+        {
+          return -1;
+        }
+
+      mask >>= 1;
+      reg++;
+    }
+
+  if (!load_sp)
+    {
+      ctrl->vrs[SP] = (unsigned long)vsp;
+    }
+
+  return 0;
+}
+
+nosanitize_address
+static int unwind_exec_pop_r4_to_rn(struct unwind_ctrl_s *ctrl,
+                                    unsigned long content)
+{
+  unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+  int reg;
+
+  /* pop R4-R[4+bbb] */
+
+  for (reg = 4; reg <= 4 + (content & 7); reg++)
+    {
+      if (unwind_pop_register(ctrl, &vsp, reg))
+        {
+          return -1;
+        }
+    }
+
+  if ((content & 0x8) && unwind_pop_register(ctrl, &vsp, 14))
+    {
+      return -1;
+    }
+
+  ctrl->vrs[SP] = (unsigned long)vsp;
+
+  return 0;
+}
+
+nosanitize_address
+static int unwind_exec_pop_subset_r0_to_r3(struct unwind_ctrl_s *ctrl,
+                                           unsigned long mask)
+{
+  unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+  int reg = 0;
+
+  /* pop R0-R3 according to mask */
+
+  while (mask)
+    {
+      if ((mask & 1) && unwind_pop_register(ctrl, &vsp, reg))
+        {
+          return -1;
+        }
+
+      mask >>= 1;
+      reg++;
+    }
+
+  ctrl->vrs[SP] = (unsigned long)vsp;
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Execute the current unwind instruction
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static int unwind_exec_content(struct unwind_ctrl_s *ctrl)
+{
+  unsigned long content = unwind_get_byte(ctrl);
+  int ret = 0;
+
+  if ((content & 0xc0) == 0x00)
+    {
+      ctrl->vrs[SP] += ((content & 0x3f) << 2) + 4;
+    }
+  else if ((content & 0xc0) == 0x40)
+    {
+      ctrl->vrs[SP] -= ((content & 0x3f) << 2) + 4;
+    }
+  else if ((content & 0xf0) == 0x80)
+    {
+      unsigned long mask;
+
+      content = (content << 8) | unwind_get_byte(ctrl);
+      mask = content & 0x0fff;
+      ret = (mask == 0) ? -1 :
+            unwind_exec_pop_subset_r4_to_r13(ctrl, mask);
+    }
+  else if ((content & 0xf0) == 0x90 &&
+           (content & 0x0d) != 0x0d)
+    {
+      ctrl->vrs[SP] = ctrl->vrs[content & 0x0f];
+    }
+  else if ((content & 0xf0) == 0xa0)
+    {
+      ret = unwind_exec_pop_r4_to_rn(ctrl, content);
+    }
+  else if (content == 0xb0)
+    {
+      if (ctrl->vrs[PC] == 0)
+        {
+          ctrl->vrs[PC] = ctrl->vrs[LR];
+        }
+
+      /* no further processing */
+
+      ctrl->entries = 0;
+    }
+  else if (content == 0xb1)
+    {
+      unsigned long mask = unwind_get_byte(ctrl);
+
+      if (mask == 0 || mask & 0xf0)
+        {
+          ret = -1;
+        }
+      else
+        {
+          ret = unwind_exec_pop_subset_r0_to_r3(ctrl, mask);
+        }
+    }
+  else if (content == 0xb2)
+    {
+      unsigned long uleb128 = unwind_get_byte(ctrl);
+
+      ctrl->vrs[SP] += 0x204 + (uleb128 << 2);
+    }
+  else
+    {
+      ret = -1;
+    }
+
+  return ret;
+}
+
+nosanitize_address
+int unwind_frame(struct unwind_frame_s *frame)
+{
+  const struct __EIT_entry *entry;
+  struct unwind_ctrl_s ctrl;
+
+  entry = unwind_find_entry(frame->pc);
+  if (!entry || entry->content == 1)
+    {
+      return -1;
+    }
+
+  ctrl.vrs[FP] = frame->fp;
+  ctrl.vrs[SP] = frame->sp;
+  ctrl.vrs[LR] = frame->lr;
+  ctrl.vrs[PC] = 0;
+  ctrl.stack_top = frame->stack_top;
+
+  if (frame->pc == prel31_to_addr(&entry->fnoffset))
+    {
+      /* Unwinding is tricky when we're halfway through the prologue,
+       * since the stack frame that the unwinder expects may not be
+       * fully set up yet. However, one thing we do know for sure is
+       * that if we are unwinding from the very first instruction of
+       * a function, we are still effectively in the stack frame of
+       * the caller, and the unwind info has no relevance yet.
+       */
+
+      if (frame->pc == frame->lr)
+        {
+          return -1;
+        }
+
+      frame->pc = frame->lr;
+
+      return 0;
+    }
+  else if ((entry->content & 0x80000000) == 0)
+    {
+      /* prel31 to the unwind table */
+
+      ctrl.insn = (unsigned long *)prel31_to_addr(&entry->content);
+    }
+  else if ((entry->content & 0xff000000) == 0x80000000)
+    {
+      /* only personality routine 0 supported in the index */
+
+      ctrl.insn = &entry->content;
+    }
+  else
+    {
+      return -1;
+    }
+
+  /* check the personality routine */
+
+  if ((*ctrl.insn & 0xff000000) == 0x80000000)
+    {
+      ctrl.byte = 2;
+      ctrl.entries = 1;
+    }
+  else if ((*ctrl.insn & 0xff000000) == 0x81000000)
+    {
+      ctrl.byte = 1;
+      ctrl.entries = 1 + ((*ctrl.insn & 0x00ff0000) >> 16);
+    }
+  else
+    {
+      return -1;
+    }
+
+  ctrl.check_each_pop = 0;
+
+  while (ctrl.entries > 0)
+    {
+      int urc;
+
+      if ((ctrl.stack_top - ctrl.vrs[SP]) < sizeof(ctrl.vrs))
+        {
+          ctrl.check_each_pop = 1;
+        }
+
+      urc = unwind_exec_content(&ctrl);
+      if (urc < 0)
+        {
+          return urc;
+        }
+
+      if (ctrl.vrs[SP] < frame->sp ||
+          ctrl.vrs[SP] > ctrl.stack_top)
+        {
+          return -1;
+        }
+    }
+
+  if (ctrl.vrs[PC] == 0)
+    {
+      ctrl.vrs[PC] = ctrl.vrs[LR];
+    }
+
+  /* check for infinite loop */
+
+  if (frame->pc == ctrl.vrs[PC] && frame->sp == ctrl.vrs[SP])
+    {
+      return -1;
+    }
+
+  frame->fp = ctrl.vrs[FP];
+  frame->sp = ctrl.vrs[SP];
+  frame->lr = ctrl.vrs[LR];
+  frame->pc = ctrl.vrs[PC];
+  frame->lr_addr = ctrl.lr_addr;
+
+  return 0;
+}
+
+nosanitize_address
+static int backtrace_unwind(struct unwind_frame_s *frame,
+                            void **buffer, int size, int *skip)
+{
+  int cnt = 0;
+
+  if (frame->pc && cnt < size && (*skip)-- <= 0)
+    {
+      buffer[cnt++] = (FAR void *)((frame->pc & ~1) - 2);
+    }
+
+  if (frame->lr && cnt < size && (*skip)-- <= 0)
+    {
+      buffer[cnt++] = (FAR void *)((frame->lr & ~1) - 2);
+    }
+
+  while (cnt < size)
+    {
+      if (unwind_frame(frame) < 0 || frame->pc == 0)
+        {
+          break;
+        }
+
+      if ((*skip)-- <= 0)
+        {
+          frame->pc = (frame->pc & ~1) - 2;
+
+          if (cnt == 0 || (FAR void *)frame->pc != buffer[cnt - 1])

Review Comment:
   remove all FAR



##########
arch/arm/src/common/arm_backtrace_unwind.c:
##########
@@ -0,0 +1,680 @@
+/****************************************************************************
+ * arch/arm/src/common/arm_backtrace_unwind.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 <arch/elf.h>
+
+#include "sched/sched.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum regs
+{
+#ifdef CONFIG_ARM_THUMB
+  FP = 7,
+#else
+  FP = 11,
+#endif /* CONFIG_ARM_THUMB */
+  SP = 13,
+  LR = 14,
+  PC = 15
+};
+
+/****************************************************************************
+ * Private Data Types
+ ****************************************************************************/
+
+struct unwind_frame_s
+{
+  unsigned long fp;
+  unsigned long sp;
+  unsigned long lr;
+  unsigned long pc;
+
+  /* address of the LR value on the stack */
+
+  unsigned long *lr_addr;
+
+  /* highest value of sp allowed */
+
+  unsigned long stack_top;
+};
+
+struct unwind_ctrl_s
+{
+  unsigned long        vrs[16];   /* virtual register set */
+  const unsigned long *insn;      /* pointer to the current instructions word */
+  unsigned long        stack_top; /* highest value of sp allowed */
+  unsigned long       *lr_addr;   /* address of LR value on the stack */
+  int                  entries;   /* number of entries left to interpret */
+  int                  byte;      /* current byte number in the instructions word */
+
+  /* 1 : check for stack overflow for each register pop.
+   * 0 : save overhead if there is plenty of stack remaining.
+   */
+
+  int check_each_pop;
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Convert a prel31 symbol to an absolute address */
+
+#define prel31_to_addr(ptr)  \
+  ({  \
+  /* sign-extend to 32 bits */  \
+  long offset = (((long)*(ptr)) << 1) >> 1;  \
+  (unsigned long)(ptr) + offset;  \
+  })
+
+/****************************************************************************
+ * Name: search_index
+ *
+ * Description:
+ *  Binary search in the unwind index. The entries are
+ *  guaranteed to be sorted in ascending order by the linker.
+ *
+ *  start    = first entry
+ *  origin   = first entry with positive offset
+ *             (or stop if there is no such entry)
+ *  stop - 1 = last entry
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static const struct __EIT_entry *
+search_index(unsigned long addr, const struct __EIT_entry *start,
+             const struct __EIT_entry *origin,
+             const struct __EIT_entry *stop)
+{
+  unsigned long addr_prel31;
+
+  /* only search in the section with the matching sign. This way the
+   * prel31 numbers can be compared as unsigned longs.
+   */
+
+  if (addr < (unsigned long)start)
+    {
+      /* negative offsets: [start; origin) */
+
+      stop = origin;
+    }
+  else
+    {
+      /* positive offsets: [origin; stop) */
+
+      start = origin;
+    }
+
+  /* prel31 for address relavive to start */
+
+  addr_prel31 = (addr - (unsigned long)start) & 0x7fffffff;
+
+  while (start < stop - 1)
+    {
+      const struct __EIT_entry *mid = start + ((stop - start) >> 1);
+
+      /* As addr_prel31 is relative to start an offset is needed to
+       * make it relative to mid.
+       */
+
+      if (addr_prel31 -
+          ((unsigned long)mid - (unsigned long)start) < mid->fnoffset)
+        {
+          stop = mid;
+        }
+      else
+        {
+          /* keep addr_prel31 relative to start */
+
+          addr_prel31 -= ((unsigned long)mid - (unsigned long)start);
+          start = mid;
+        }
+    }
+
+  return (start->fnoffset <= addr_prel31) ? start : NULL;
+}
+
+nosanitize_address
+static const struct __EIT_entry *
+unwind_find_origin(const struct __EIT_entry *start,
+                   const struct __EIT_entry *stop)
+{
+  const struct __EIT_entry *mid;
+
+  while (start < stop)
+    {
+      mid = start + ((stop - start) >> 1);
+
+      if (mid->fnoffset >= 0x40000000)
+        {
+          /* negative offset */
+
+          start = mid + 1;
+        }
+      else
+        {
+          /* positive offset */
+
+          stop = mid;
+        }
+    }
+
+  return stop;
+}
+
+nosanitize_address
+static const struct __EIT_entry *unwind_find_entry(unsigned long addr)
+{
+  /* main unwind table */
+
+  return search_index(addr, __exidx_start,
+                      unwind_find_origin(__exidx_start, __exidx_end),
+                      __exidx_end);
+}
+
+nosanitize_address
+static unsigned long unwind_get_byte(struct unwind_ctrl_s *ctrl)
+{
+  unsigned long ret;
+
+  if (ctrl->entries <= 0)
+    {
+      return 0;
+    }
+
+  ret = (*ctrl->insn >> (ctrl->byte * 8)) & 0xff;
+
+  if (ctrl->byte == 0)
+    {
+      ctrl->insn++;
+      ctrl->entries--;
+      ctrl->byte = 3;
+    }
+  else
+    {
+      ctrl->byte--;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Before poping a register check whether it is feasible or not
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static int unwind_pop_register(struct unwind_ctrl_s *ctrl,
+                               unsigned long **vsp, unsigned int reg)
+{
+  if (ctrl->check_each_pop)
+    {
+      if (*vsp >= (unsigned long *)ctrl->stack_top)
+        {
+          return -1;
+        }
+    }
+
+  /* Use READ_ONCE_NOCHECK here to avoid this memory access
+   * from being tracked by KASAN.
+   */
+
+  ctrl->vrs[reg] = *(*vsp);
+  if (reg == LR)
+    {
+      ctrl->lr_addr = *vsp;
+    }
+
+  (*vsp)++;
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Helper functions to execute the instructions
+ *
+ ****************************************************************************/
+
+nosanitize_address static int
+unwind_exec_pop_subset_r4_to_r13(struct unwind_ctrl_s *ctrl,
+                                 unsigned long mask)
+{
+  unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+  int load_sp;
+  int reg = 4;
+
+  load_sp = mask & (1 << (13 - 4));
+  while (mask)
+    {
+      if ((mask & 1) && unwind_pop_register(ctrl, &vsp, reg))
+        {
+          return -1;
+        }
+
+      mask >>= 1;
+      reg++;
+    }
+
+  if (!load_sp)
+    {
+      ctrl->vrs[SP] = (unsigned long)vsp;
+    }
+
+  return 0;
+}
+
+nosanitize_address
+static int unwind_exec_pop_r4_to_rn(struct unwind_ctrl_s *ctrl,
+                                    unsigned long content)
+{
+  unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+  int reg;
+
+  /* pop R4-R[4+bbb] */
+
+  for (reg = 4; reg <= 4 + (content & 7); reg++)
+    {
+      if (unwind_pop_register(ctrl, &vsp, reg))
+        {
+          return -1;
+        }
+    }
+
+  if ((content & 0x8) && unwind_pop_register(ctrl, &vsp, 14))
+    {
+      return -1;
+    }
+
+  ctrl->vrs[SP] = (unsigned long)vsp;
+
+  return 0;
+}
+
+nosanitize_address
+static int unwind_exec_pop_subset_r0_to_r3(struct unwind_ctrl_s *ctrl,
+                                           unsigned long mask)
+{
+  unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+  int reg = 0;
+
+  /* pop R0-R3 according to mask */
+
+  while (mask)
+    {
+      if ((mask & 1) && unwind_pop_register(ctrl, &vsp, reg))
+        {
+          return -1;
+        }
+
+      mask >>= 1;
+      reg++;
+    }
+
+  ctrl->vrs[SP] = (unsigned long)vsp;
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Execute the current unwind instruction
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static int unwind_exec_content(struct unwind_ctrl_s *ctrl)
+{
+  unsigned long content = unwind_get_byte(ctrl);
+  int ret = 0;
+
+  if ((content & 0xc0) == 0x00)
+    {
+      ctrl->vrs[SP] += ((content & 0x3f) << 2) + 4;
+    }
+  else if ((content & 0xc0) == 0x40)
+    {
+      ctrl->vrs[SP] -= ((content & 0x3f) << 2) + 4;
+    }
+  else if ((content & 0xf0) == 0x80)
+    {
+      unsigned long mask;
+
+      content = (content << 8) | unwind_get_byte(ctrl);
+      mask = content & 0x0fff;
+      ret = (mask == 0) ? -1 :
+            unwind_exec_pop_subset_r4_to_r13(ctrl, mask);
+    }
+  else if ((content & 0xf0) == 0x90 &&
+           (content & 0x0d) != 0x0d)
+    {
+      ctrl->vrs[SP] = ctrl->vrs[content & 0x0f];
+    }
+  else if ((content & 0xf0) == 0xa0)
+    {
+      ret = unwind_exec_pop_r4_to_rn(ctrl, content);
+    }
+  else if (content == 0xb0)
+    {
+      if (ctrl->vrs[PC] == 0)
+        {
+          ctrl->vrs[PC] = ctrl->vrs[LR];
+        }
+
+      /* no further processing */
+
+      ctrl->entries = 0;
+    }
+  else if (content == 0xb1)
+    {
+      unsigned long mask = unwind_get_byte(ctrl);
+
+      if (mask == 0 || mask & 0xf0)
+        {
+          ret = -1;
+        }
+      else
+        {
+          ret = unwind_exec_pop_subset_r0_to_r3(ctrl, mask);
+        }
+    }
+  else if (content == 0xb2)
+    {
+      unsigned long uleb128 = unwind_get_byte(ctrl);
+
+      ctrl->vrs[SP] += 0x204 + (uleb128 << 2);
+    }
+  else
+    {
+      ret = -1;
+    }
+
+  return ret;
+}
+
+nosanitize_address
+int unwind_frame(struct unwind_frame_s *frame)
+{
+  const struct __EIT_entry *entry;

Review Comment:
   remove, define in arch/elf.h



##########
arch/arm/src/common/arm_backtrace_unwind.c:
##########
@@ -0,0 +1,680 @@
+/****************************************************************************
+ * arch/arm/src/common/arm_backtrace_unwind.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 <arch/elf.h>
+
+#include "sched/sched.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum regs
+{
+#ifdef CONFIG_ARM_THUMB
+  FP = 7,
+#else
+  FP = 11,
+#endif /* CONFIG_ARM_THUMB */
+  SP = 13,
+  LR = 14,
+  PC = 15
+};
+
+/****************************************************************************
+ * Private Data Types
+ ****************************************************************************/
+
+struct unwind_frame_s
+{
+  unsigned long fp;
+  unsigned long sp;
+  unsigned long lr;
+  unsigned long pc;
+
+  /* address of the LR value on the stack */
+
+  unsigned long *lr_addr;
+
+  /* highest value of sp allowed */
+
+  unsigned long stack_top;
+};
+
+struct unwind_ctrl_s
+{
+  unsigned long        vrs[16];   /* virtual register set */
+  const unsigned long *insn;      /* pointer to the current instructions word */
+  unsigned long        stack_top; /* highest value of sp allowed */
+  unsigned long       *lr_addr;   /* address of LR value on the stack */
+  int                  entries;   /* number of entries left to interpret */
+  int                  byte;      /* current byte number in the instructions word */
+
+  /* 1 : check for stack overflow for each register pop.
+   * 0 : save overhead if there is plenty of stack remaining.
+   */
+
+  int check_each_pop;
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Convert a prel31 symbol to an absolute address */
+
+#define prel31_to_addr(ptr)  \
+  ({  \
+  /* sign-extend to 32 bits */  \
+  long offset = (((long)*(ptr)) << 1) >> 1;  \
+  (unsigned long)(ptr) + offset;  \
+  })
+
+/****************************************************************************
+ * Name: search_index
+ *
+ * Description:
+ *  Binary search in the unwind index. The entries are
+ *  guaranteed to be sorted in ascending order by the linker.
+ *
+ *  start    = first entry
+ *  origin   = first entry with positive offset
+ *             (or stop if there is no such entry)
+ *  stop - 1 = last entry
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static const struct __EIT_entry *
+search_index(unsigned long addr, const struct __EIT_entry *start,
+             const struct __EIT_entry *origin,
+             const struct __EIT_entry *stop)
+{
+  unsigned long addr_prel31;
+
+  /* only search in the section with the matching sign. This way the
+   * prel31 numbers can be compared as unsigned longs.
+   */
+
+  if (addr < (unsigned long)start)
+    {
+      /* negative offsets: [start; origin) */
+
+      stop = origin;
+    }
+  else
+    {
+      /* positive offsets: [origin; stop) */
+
+      start = origin;
+    }
+
+  /* prel31 for address relavive to start */
+
+  addr_prel31 = (addr - (unsigned long)start) & 0x7fffffff;
+
+  while (start < stop - 1)
+    {
+      const struct __EIT_entry *mid = start + ((stop - start) >> 1);
+
+      /* As addr_prel31 is relative to start an offset is needed to
+       * make it relative to mid.
+       */
+
+      if (addr_prel31 -
+          ((unsigned long)mid - (unsigned long)start) < mid->fnoffset)
+        {
+          stop = mid;
+        }
+      else
+        {
+          /* keep addr_prel31 relative to start */
+
+          addr_prel31 -= ((unsigned long)mid - (unsigned long)start);
+          start = mid;
+        }
+    }
+
+  return (start->fnoffset <= addr_prel31) ? start : NULL;
+}
+
+nosanitize_address
+static const struct __EIT_entry *
+unwind_find_origin(const struct __EIT_entry *start,
+                   const struct __EIT_entry *stop)
+{
+  const struct __EIT_entry *mid;
+
+  while (start < stop)
+    {
+      mid = start + ((stop - start) >> 1);
+
+      if (mid->fnoffset >= 0x40000000)
+        {
+          /* negative offset */
+
+          start = mid + 1;
+        }
+      else
+        {
+          /* positive offset */
+
+          stop = mid;
+        }
+    }
+
+  return stop;
+}
+
+nosanitize_address
+static const struct __EIT_entry *unwind_find_entry(unsigned long addr)
+{
+  /* main unwind table */
+
+  return search_index(addr, __exidx_start,
+                      unwind_find_origin(__exidx_start, __exidx_end),
+                      __exidx_end);
+}
+
+nosanitize_address
+static unsigned long unwind_get_byte(struct unwind_ctrl_s *ctrl)
+{
+  unsigned long ret;
+
+  if (ctrl->entries <= 0)
+    {
+      return 0;
+    }
+
+  ret = (*ctrl->insn >> (ctrl->byte * 8)) & 0xff;
+
+  if (ctrl->byte == 0)
+    {
+      ctrl->insn++;
+      ctrl->entries--;
+      ctrl->byte = 3;
+    }
+  else
+    {
+      ctrl->byte--;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Before poping a register check whether it is feasible or not
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static int unwind_pop_register(struct unwind_ctrl_s *ctrl,
+                               unsigned long **vsp, unsigned int reg)
+{
+  if (ctrl->check_each_pop)
+    {
+      if (*vsp >= (unsigned long *)ctrl->stack_top)
+        {
+          return -1;
+        }
+    }
+
+  /* Use READ_ONCE_NOCHECK here to avoid this memory access
+   * from being tracked by KASAN.
+   */
+
+  ctrl->vrs[reg] = *(*vsp);
+  if (reg == LR)
+    {
+      ctrl->lr_addr = *vsp;
+    }
+
+  (*vsp)++;
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Helper functions to execute the instructions
+ *
+ ****************************************************************************/
+
+nosanitize_address static int
+unwind_exec_pop_subset_r4_to_r13(struct unwind_ctrl_s *ctrl,
+                                 unsigned long mask)
+{
+  unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+  int load_sp;
+  int reg = 4;
+
+  load_sp = mask & (1 << (13 - 4));
+  while (mask)
+    {
+      if ((mask & 1) && unwind_pop_register(ctrl, &vsp, reg))
+        {
+          return -1;
+        }
+
+      mask >>= 1;
+      reg++;
+    }
+
+  if (!load_sp)
+    {
+      ctrl->vrs[SP] = (unsigned long)vsp;
+    }
+
+  return 0;
+}
+
+nosanitize_address
+static int unwind_exec_pop_r4_to_rn(struct unwind_ctrl_s *ctrl,
+                                    unsigned long content)
+{
+  unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+  int reg;
+
+  /* pop R4-R[4+bbb] */
+
+  for (reg = 4; reg <= 4 + (content & 7); reg++)
+    {
+      if (unwind_pop_register(ctrl, &vsp, reg))
+        {
+          return -1;
+        }
+    }
+
+  if ((content & 0x8) && unwind_pop_register(ctrl, &vsp, 14))
+    {
+      return -1;
+    }
+
+  ctrl->vrs[SP] = (unsigned long)vsp;
+
+  return 0;
+}
+
+nosanitize_address
+static int unwind_exec_pop_subset_r0_to_r3(struct unwind_ctrl_s *ctrl,
+                                           unsigned long mask)
+{
+  unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+  int reg = 0;
+
+  /* pop R0-R3 according to mask */
+
+  while (mask)
+    {
+      if ((mask & 1) && unwind_pop_register(ctrl, &vsp, reg))
+        {
+          return -1;
+        }
+
+      mask >>= 1;
+      reg++;
+    }
+
+  ctrl->vrs[SP] = (unsigned long)vsp;
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Execute the current unwind instruction
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static int unwind_exec_content(struct unwind_ctrl_s *ctrl)
+{
+  unsigned long content = unwind_get_byte(ctrl);
+  int ret = 0;
+
+  if ((content & 0xc0) == 0x00)
+    {
+      ctrl->vrs[SP] += ((content & 0x3f) << 2) + 4;
+    }
+  else if ((content & 0xc0) == 0x40)
+    {
+      ctrl->vrs[SP] -= ((content & 0x3f) << 2) + 4;
+    }
+  else if ((content & 0xf0) == 0x80)
+    {
+      unsigned long mask;
+
+      content = (content << 8) | unwind_get_byte(ctrl);
+      mask = content & 0x0fff;
+      ret = (mask == 0) ? -1 :
+            unwind_exec_pop_subset_r4_to_r13(ctrl, mask);
+    }
+  else if ((content & 0xf0) == 0x90 &&
+           (content & 0x0d) != 0x0d)
+    {
+      ctrl->vrs[SP] = ctrl->vrs[content & 0x0f];
+    }
+  else if ((content & 0xf0) == 0xa0)
+    {
+      ret = unwind_exec_pop_r4_to_rn(ctrl, content);
+    }
+  else if (content == 0xb0)
+    {
+      if (ctrl->vrs[PC] == 0)
+        {
+          ctrl->vrs[PC] = ctrl->vrs[LR];
+        }
+
+      /* no further processing */
+
+      ctrl->entries = 0;
+    }
+  else if (content == 0xb1)
+    {
+      unsigned long mask = unwind_get_byte(ctrl);
+
+      if (mask == 0 || mask & 0xf0)
+        {
+          ret = -1;
+        }
+      else
+        {
+          ret = unwind_exec_pop_subset_r0_to_r3(ctrl, mask);
+        }
+    }
+  else if (content == 0xb2)
+    {
+      unsigned long uleb128 = unwind_get_byte(ctrl);
+
+      ctrl->vrs[SP] += 0x204 + (uleb128 << 2);
+    }
+  else
+    {
+      ret = -1;
+    }
+
+  return ret;
+}
+
+nosanitize_address
+int unwind_frame(struct unwind_frame_s *frame)
+{
+  const struct __EIT_entry *entry;
+  struct unwind_ctrl_s ctrl;
+
+  entry = unwind_find_entry(frame->pc);
+  if (!entry || entry->content == 1)
+    {
+      return -1;
+    }
+
+  ctrl.vrs[FP] = frame->fp;
+  ctrl.vrs[SP] = frame->sp;
+  ctrl.vrs[LR] = frame->lr;
+  ctrl.vrs[PC] = 0;
+  ctrl.stack_top = frame->stack_top;
+
+  if (frame->pc == prel31_to_addr(&entry->fnoffset))
+    {
+      /* Unwinding is tricky when we're halfway through the prologue,
+       * since the stack frame that the unwinder expects may not be
+       * fully set up yet. However, one thing we do know for sure is
+       * that if we are unwinding from the very first instruction of
+       * a function, we are still effectively in the stack frame of
+       * the caller, and the unwind info has no relevance yet.
+       */
+
+      if (frame->pc == frame->lr)
+        {
+          return -1;
+        }
+
+      frame->pc = frame->lr;
+
+      return 0;
+    }
+  else if ((entry->content & 0x80000000) == 0)
+    {
+      /* prel31 to the unwind table */
+
+      ctrl.insn = (unsigned long *)prel31_to_addr(&entry->content);
+    }
+  else if ((entry->content & 0xff000000) == 0x80000000)
+    {
+      /* only personality routine 0 supported in the index */
+
+      ctrl.insn = &entry->content;
+    }
+  else
+    {
+      return -1;
+    }
+
+  /* check the personality routine */
+
+  if ((*ctrl.insn & 0xff000000) == 0x80000000)
+    {
+      ctrl.byte = 2;
+      ctrl.entries = 1;
+    }
+  else if ((*ctrl.insn & 0xff000000) == 0x81000000)
+    {
+      ctrl.byte = 1;
+      ctrl.entries = 1 + ((*ctrl.insn & 0x00ff0000) >> 16);
+    }
+  else
+    {
+      return -1;
+    }
+
+  ctrl.check_each_pop = 0;
+
+  while (ctrl.entries > 0)
+    {
+      int urc;
+
+      if ((ctrl.stack_top - ctrl.vrs[SP]) < sizeof(ctrl.vrs))
+        {
+          ctrl.check_each_pop = 1;
+        }
+
+      urc = unwind_exec_content(&ctrl);
+      if (urc < 0)
+        {
+          return urc;
+        }
+
+      if (ctrl.vrs[SP] < frame->sp ||
+          ctrl.vrs[SP] > ctrl.stack_top)
+        {
+          return -1;
+        }
+    }
+
+  if (ctrl.vrs[PC] == 0)
+    {
+      ctrl.vrs[PC] = ctrl.vrs[LR];
+    }
+
+  /* check for infinite loop */
+
+  if (frame->pc == ctrl.vrs[PC] && frame->sp == ctrl.vrs[SP])
+    {
+      return -1;
+    }
+
+  frame->fp = ctrl.vrs[FP];
+  frame->sp = ctrl.vrs[SP];
+  frame->lr = ctrl.vrs[LR];
+  frame->pc = ctrl.vrs[PC];
+  frame->lr_addr = ctrl.lr_addr;
+
+  return 0;
+}
+
+nosanitize_address
+static int backtrace_unwind(struct unwind_frame_s *frame,
+                            void **buffer, int size, int *skip)
+{
+  int cnt = 0;
+
+  if (frame->pc && cnt < size && (*skip)-- <= 0)
+    {
+      buffer[cnt++] = (FAR void *)((frame->pc & ~1) - 2);
+    }
+
+  if (frame->lr && cnt < size && (*skip)-- <= 0)
+    {
+      buffer[cnt++] = (FAR void *)((frame->lr & ~1) - 2);
+    }
+
+  while (cnt < size)
+    {
+      if (unwind_frame(frame) < 0 || frame->pc == 0)
+        {
+          break;
+        }
+
+      if ((*skip)-- <= 0)
+        {
+          frame->pc = (frame->pc & ~1) - 2;
+
+          if (cnt == 0 || (FAR void *)frame->pc != buffer[cnt - 1])
+            {
+              buffer[cnt++] = (FAR void *)frame->pc;
+            }
+        }
+    }
+
+  return cnt > 0 ? cnt : 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_backtrace
+ *
+ * Description:
+ *  up_backtrace()  returns  a backtrace for the TCB, in the array
+ *  pointed to by buffer.  A backtrace is the series of currently active
+ *  function calls for the program.  Each item in the array pointed to by
+ *  buffer is of type void *, and is the return address from the
+ *  corresponding stack frame.  The size argument specifies the maximum
+ *  number of addresses that can be stored in buffer.   If  the backtrace is
+ *  larger than size, then the addresses corresponding to the size most
+ *  recent function calls are returned; to obtain the complete backtrace,
+ *  make sure that buffer and size are large enough.
+ *
+ * Input Parameters:
+ *   tcb    - Address of the task's TCB
+ *   buffer - Return address from the corresponding stack frame
+ *   size   - Maximum number of addresses that can be stored in buffer
+ *   skip   - number of addresses to be skipped
+ *
+ * Returned Value:
+ *   up_backtrace() returns the number of addresses returned in buffer
+ *
+ ****************************************************************************/
+
+nosanitize_address
+int up_backtrace(struct tcb_s *tcb,
+                 void **buffer, int size, int skip)
+{
+  struct tcb_s *rtcb = running_task();
+  struct unwind_frame_s frame;
+  irqstate_t flags;
+  int ret;
+
+  if (size <= 0 || !buffer)
+    {
+      return 0;
+    }
+
+  if (tcb == NULL || tcb == rtcb)
+    {
+      frame.fp = (unsigned long)__builtin_frame_address(0);
+      frame.lr = (unsigned long)__builtin_return_address(0);
+      frame.pc = (unsigned long)&up_backtrace;
+      frame.sp = frame.fp;
+      frame.stack_top = (unsigned long)rtcb->stack_base_ptr +
+                                       rtcb->adj_stack_size;

Review Comment:
   move after line 659



-- 
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-unsubscribe@nuttx.apache.org

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


[GitHub] [incubator-nuttx] xiaoxiang781216 commented on a diff in pull request #7260: arm/backtrace: add support for EHABI(Exception Handling ABI) stack unwinder

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 commented on code in PR #7260:
URL: https://github.com/apache/incubator-nuttx/pull/7260#discussion_r990768956


##########
arch/arm/src/common/arm_backtrace_unwind.c:
##########
@@ -0,0 +1,680 @@
+/****************************************************************************
+ * arch/arm/src/common/arm_backtrace_unwind.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 <arch/elf.h>
+
+#include "sched/sched.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum regs
+{
+#ifdef CONFIG_ARM_THUMB
+  FP = 7,
+#else
+  FP = 11,
+#endif /* CONFIG_ARM_THUMB */
+  SP = 13,
+  LR = 14,
+  PC = 15
+};
+
+/****************************************************************************
+ * Private Data Types
+ ****************************************************************************/
+
+struct unwind_frame_s
+{
+  unsigned long fp;
+  unsigned long sp;
+  unsigned long lr;
+  unsigned long pc;
+
+  /* address of the LR value on the stack */
+
+  unsigned long *lr_addr;
+
+  /* highest value of sp allowed */
+
+  unsigned long stack_top;
+};
+
+struct unwind_ctrl_s
+{
+  unsigned long        vrs[16];   /* virtual register set */
+  const unsigned long *insn;      /* pointer to the current instructions word */
+  unsigned long        stack_top; /* highest value of sp allowed */
+  unsigned long       *lr_addr;   /* address of LR value on the stack */
+  int                  entries;   /* number of entries left to interpret */
+  int                  byte;      /* current byte number in the instructions word */
+
+  /* 1 : check for stack overflow for each register pop.
+   * 0 : save overhead if there is plenty of stack remaining.
+   */
+
+  int check_each_pop;
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Convert a prel31 symbol to an absolute address */
+
+#define prel31_to_addr(ptr)  \
+  ({  \
+  /* sign-extend to 32 bits */  \
+  long offset = (((long)*(ptr)) << 1) >> 1;  \
+  (unsigned long)(ptr) + offset;  \
+  })
+
+/****************************************************************************
+ * Name: search_index
+ *
+ * Description:
+ *  Binary search in the unwind index. The entries are
+ *  guaranteed to be sorted in ascending order by the linker.
+ *
+ *  start    = first entry
+ *  origin   = first entry with positive offset
+ *             (or stop if there is no such entry)
+ *  stop - 1 = last entry
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static const struct __EIT_entry *
+search_index(unsigned long addr, const struct __EIT_entry *start,
+             const struct __EIT_entry *origin,
+             const struct __EIT_entry *stop)
+{
+  unsigned long addr_prel31;
+
+  /* only search in the section with the matching sign. This way the
+   * prel31 numbers can be compared as unsigned longs.
+   */
+
+  if (addr < (unsigned long)start)
+    {
+      /* negative offsets: [start; origin) */
+
+      stop = origin;
+    }
+  else
+    {
+      /* positive offsets: [origin; stop) */
+
+      start = origin;
+    }
+
+  /* prel31 for address relavive to start */
+
+  addr_prel31 = (addr - (unsigned long)start) & 0x7fffffff;
+
+  while (start < stop - 1)
+    {
+      const struct __EIT_entry *mid = start + ((stop - start) >> 1);
+
+      /* As addr_prel31 is relative to start an offset is needed to
+       * make it relative to mid.
+       */
+
+      if (addr_prel31 -
+          ((unsigned long)mid - (unsigned long)start) < mid->fnoffset)
+        {
+          stop = mid;
+        }
+      else
+        {
+          /* keep addr_prel31 relative to start */
+
+          addr_prel31 -= ((unsigned long)mid - (unsigned long)start);
+          start = mid;
+        }
+    }
+
+  return (start->fnoffset <= addr_prel31) ? start : NULL;
+}
+
+nosanitize_address
+static const struct __EIT_entry *
+unwind_find_origin(const struct __EIT_entry *start,
+                   const struct __EIT_entry *stop)
+{
+  const struct __EIT_entry *mid;
+
+  while (start < stop)
+    {
+      mid = start + ((stop - start) >> 1);
+
+      if (mid->fnoffset >= 0x40000000)
+        {
+          /* negative offset */
+
+          start = mid + 1;
+        }
+      else
+        {
+          /* positive offset */
+
+          stop = mid;
+        }
+    }
+
+  return stop;
+}
+
+nosanitize_address
+static const struct __EIT_entry *unwind_find_entry(unsigned long addr)
+{
+  /* main unwind table */
+
+  return search_index(addr, __exidx_start,
+                      unwind_find_origin(__exidx_start, __exidx_end),
+                      __exidx_end);
+}
+
+nosanitize_address
+static unsigned long unwind_get_byte(struct unwind_ctrl_s *ctrl)
+{
+  unsigned long ret;
+
+  if (ctrl->entries <= 0)
+    {
+      return 0;
+    }
+
+  ret = (*ctrl->insn >> (ctrl->byte * 8)) & 0xff;
+
+  if (ctrl->byte == 0)
+    {
+      ctrl->insn++;
+      ctrl->entries--;
+      ctrl->byte = 3;
+    }
+  else
+    {
+      ctrl->byte--;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Before poping a register check whether it is feasible or not
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static int unwind_pop_register(struct unwind_ctrl_s *ctrl,
+                               unsigned long **vsp, unsigned int reg)
+{
+  if (ctrl->check_each_pop)
+    {
+      if (*vsp >= (unsigned long *)ctrl->stack_top)
+        {
+          return -1;
+        }
+    }
+
+  /* Use READ_ONCE_NOCHECK here to avoid this memory access

Review Comment:
   remove



##########
arch/arm/src/common/arm_backtrace_unwind.c:
##########
@@ -0,0 +1,680 @@
+/****************************************************************************
+ * arch/arm/src/common/arm_backtrace_unwind.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 <arch/elf.h>
+
+#include "sched/sched.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum regs
+{
+#ifdef CONFIG_ARM_THUMB
+  FP = 7,
+#else
+  FP = 11,
+#endif /* CONFIG_ARM_THUMB */
+  SP = 13,
+  LR = 14,
+  PC = 15
+};
+
+/****************************************************************************
+ * Private Data Types
+ ****************************************************************************/
+
+struct unwind_frame_s
+{
+  unsigned long fp;
+  unsigned long sp;
+  unsigned long lr;
+  unsigned long pc;
+
+  /* address of the LR value on the stack */
+
+  unsigned long *lr_addr;
+
+  /* highest value of sp allowed */
+
+  unsigned long stack_top;
+};
+
+struct unwind_ctrl_s
+{
+  unsigned long        vrs[16];   /* virtual register set */
+  const unsigned long *insn;      /* pointer to the current instructions word */
+  unsigned long        stack_top; /* highest value of sp allowed */
+  unsigned long       *lr_addr;   /* address of LR value on the stack */
+  int                  entries;   /* number of entries left to interpret */
+  int                  byte;      /* current byte number in the instructions word */
+
+  /* 1 : check for stack overflow for each register pop.
+   * 0 : save overhead if there is plenty of stack remaining.
+   */
+
+  int check_each_pop;
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Convert a prel31 symbol to an absolute address */
+
+#define prel31_to_addr(ptr)  \
+  ({  \
+  /* sign-extend to 32 bits */  \
+  long offset = (((long)*(ptr)) << 1) >> 1;  \
+  (unsigned long)(ptr) + offset;  \
+  })
+
+/****************************************************************************
+ * Name: search_index
+ *
+ * Description:
+ *  Binary search in the unwind index. The entries are
+ *  guaranteed to be sorted in ascending order by the linker.
+ *
+ *  start    = first entry
+ *  origin   = first entry with positive offset
+ *             (or stop if there is no such entry)
+ *  stop - 1 = last entry
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static const struct __EIT_entry *
+search_index(unsigned long addr, const struct __EIT_entry *start,
+             const struct __EIT_entry *origin,
+             const struct __EIT_entry *stop)
+{
+  unsigned long addr_prel31;
+
+  /* only search in the section with the matching sign. This way the

Review Comment:
   Change all first char in comment to upper case



-- 
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-unsubscribe@nuttx.apache.org

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


[GitHub] [incubator-nuttx] anchao commented on a diff in pull request #7260: arm/backtrace: add support for EHABI(Exception Handling ABI) stack unwinder

Posted by GitBox <gi...@apache.org>.
anchao commented on code in PR #7260:
URL: https://github.com/apache/incubator-nuttx/pull/7260#discussion_r990777702


##########
arch/arm/src/common/arm_backtrace_unwind.c:
##########
@@ -0,0 +1,680 @@
+/****************************************************************************
+ * arch/arm/src/common/arm_backtrace_unwind.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 <arch/elf.h>
+
+#include "sched/sched.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum regs
+{
+#ifdef CONFIG_ARM_THUMB
+  FP = 7,
+#else
+  FP = 11,
+#endif /* CONFIG_ARM_THUMB */
+  SP = 13,
+  LR = 14,
+  PC = 15
+};
+
+/****************************************************************************
+ * Private Data Types
+ ****************************************************************************/
+
+struct unwind_frame_s
+{
+  unsigned long fp;
+  unsigned long sp;
+  unsigned long lr;
+  unsigned long pc;
+
+  /* address of the LR value on the stack */
+
+  unsigned long *lr_addr;
+
+  /* highest value of sp allowed */
+
+  unsigned long stack_top;
+};
+
+struct unwind_ctrl_s
+{
+  unsigned long        vrs[16];   /* virtual register set */
+  const unsigned long *insn;      /* pointer to the current instructions word */
+  unsigned long        stack_top; /* highest value of sp allowed */
+  unsigned long       *lr_addr;   /* address of LR value on the stack */
+  int                  entries;   /* number of entries left to interpret */
+  int                  byte;      /* current byte number in the instructions word */
+
+  /* 1 : check for stack overflow for each register pop.
+   * 0 : save overhead if there is plenty of stack remaining.
+   */
+
+  int check_each_pop;
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Convert a prel31 symbol to an absolute address */
+
+#define prel31_to_addr(ptr)  \
+  ({  \
+  /* sign-extend to 32 bits */  \
+  long offset = (((long)*(ptr)) << 1) >> 1;  \
+  (unsigned long)(ptr) + offset;  \
+  })
+
+/****************************************************************************
+ * Name: search_index
+ *
+ * Description:
+ *  Binary search in the unwind index. The entries are
+ *  guaranteed to be sorted in ascending order by the linker.
+ *
+ *  start    = first entry
+ *  origin   = first entry with positive offset
+ *             (or stop if there is no such entry)
+ *  stop - 1 = last entry
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static const struct __EIT_entry *
+search_index(unsigned long addr, const struct __EIT_entry *start,
+             const struct __EIT_entry *origin,
+             const struct __EIT_entry *stop)
+{
+  unsigned long addr_prel31;
+
+  /* only search in the section with the matching sign. This way the
+   * prel31 numbers can be compared as unsigned longs.
+   */
+
+  if (addr < (unsigned long)start)
+    {
+      /* negative offsets: [start; origin) */
+
+      stop = origin;
+    }
+  else
+    {
+      /* positive offsets: [origin; stop) */
+
+      start = origin;
+    }
+
+  /* prel31 for address relavive to start */
+
+  addr_prel31 = (addr - (unsigned long)start) & 0x7fffffff;
+
+  while (start < stop - 1)
+    {
+      const struct __EIT_entry *mid = start + ((stop - start) >> 1);
+
+      /* As addr_prel31 is relative to start an offset is needed to
+       * make it relative to mid.
+       */
+
+      if (addr_prel31 -
+          ((unsigned long)mid - (unsigned long)start) < mid->fnoffset)
+        {
+          stop = mid;
+        }
+      else
+        {
+          /* keep addr_prel31 relative to start */
+
+          addr_prel31 -= ((unsigned long)mid - (unsigned long)start);
+          start = mid;
+        }
+    }
+
+  return (start->fnoffset <= addr_prel31) ? start : NULL;
+}
+
+nosanitize_address
+static const struct __EIT_entry *
+unwind_find_origin(const struct __EIT_entry *start,
+                   const struct __EIT_entry *stop)
+{
+  const struct __EIT_entry *mid;
+
+  while (start < stop)
+    {
+      mid = start + ((stop - start) >> 1);
+
+      if (mid->fnoffset >= 0x40000000)
+        {
+          /* negative offset */
+
+          start = mid + 1;
+        }
+      else
+        {
+          /* positive offset */
+
+          stop = mid;
+        }
+    }
+
+  return stop;
+}
+
+nosanitize_address
+static const struct __EIT_entry *unwind_find_entry(unsigned long addr)
+{
+  /* main unwind table */
+
+  return search_index(addr, __exidx_start,
+                      unwind_find_origin(__exidx_start, __exidx_end),
+                      __exidx_end);
+}
+
+nosanitize_address
+static unsigned long unwind_get_byte(struct unwind_ctrl_s *ctrl)
+{
+  unsigned long ret;
+
+  if (ctrl->entries <= 0)
+    {
+      return 0;
+    }
+
+  ret = (*ctrl->insn >> (ctrl->byte * 8)) & 0xff;
+
+  if (ctrl->byte == 0)
+    {
+      ctrl->insn++;
+      ctrl->entries--;
+      ctrl->byte = 3;
+    }
+  else
+    {
+      ctrl->byte--;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Before poping a register check whether it is feasible or not
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static int unwind_pop_register(struct unwind_ctrl_s *ctrl,
+                               unsigned long **vsp, unsigned int reg)
+{
+  if (ctrl->check_each_pop)
+    {
+      if (*vsp >= (unsigned long *)ctrl->stack_top)
+        {
+          return -1;
+        }
+    }
+
+  /* Use READ_ONCE_NOCHECK here to avoid this memory access

Review Comment:
   Done



##########
arch/arm/src/common/arm_backtrace_unwind.c:
##########
@@ -0,0 +1,680 @@
+/****************************************************************************
+ * arch/arm/src/common/arm_backtrace_unwind.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 <arch/elf.h>
+
+#include "sched/sched.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum regs
+{
+#ifdef CONFIG_ARM_THUMB
+  FP = 7,
+#else
+  FP = 11,
+#endif /* CONFIG_ARM_THUMB */
+  SP = 13,
+  LR = 14,
+  PC = 15
+};
+
+/****************************************************************************
+ * Private Data Types
+ ****************************************************************************/
+
+struct unwind_frame_s
+{
+  unsigned long fp;
+  unsigned long sp;
+  unsigned long lr;
+  unsigned long pc;
+
+  /* address of the LR value on the stack */
+
+  unsigned long *lr_addr;
+
+  /* highest value of sp allowed */
+
+  unsigned long stack_top;
+};
+
+struct unwind_ctrl_s
+{
+  unsigned long        vrs[16];   /* virtual register set */
+  const unsigned long *insn;      /* pointer to the current instructions word */
+  unsigned long        stack_top; /* highest value of sp allowed */
+  unsigned long       *lr_addr;   /* address of LR value on the stack */
+  int                  entries;   /* number of entries left to interpret */
+  int                  byte;      /* current byte number in the instructions word */
+
+  /* 1 : check for stack overflow for each register pop.
+   * 0 : save overhead if there is plenty of stack remaining.
+   */
+
+  int check_each_pop;
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Convert a prel31 symbol to an absolute address */
+
+#define prel31_to_addr(ptr)  \
+  ({  \
+  /* sign-extend to 32 bits */  \
+  long offset = (((long)*(ptr)) << 1) >> 1;  \
+  (unsigned long)(ptr) + offset;  \
+  })
+
+/****************************************************************************
+ * Name: search_index
+ *
+ * Description:
+ *  Binary search in the unwind index. The entries are
+ *  guaranteed to be sorted in ascending order by the linker.
+ *
+ *  start    = first entry
+ *  origin   = first entry with positive offset
+ *             (or stop if there is no such entry)
+ *  stop - 1 = last entry
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static const struct __EIT_entry *
+search_index(unsigned long addr, const struct __EIT_entry *start,
+             const struct __EIT_entry *origin,
+             const struct __EIT_entry *stop)
+{
+  unsigned long addr_prel31;
+
+  /* only search in the section with the matching sign. This way the

Review Comment:
   Done



-- 
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-unsubscribe@nuttx.apache.org

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


[GitHub] [incubator-nuttx] anchao commented on a diff in pull request #7260: arm/backtrace: add support for EHABI(Exception Handling ABI) stack unwinder

Posted by GitBox <gi...@apache.org>.
anchao commented on code in PR #7260:
URL: https://github.com/apache/incubator-nuttx/pull/7260#discussion_r990777662


##########
arch/arm/src/common/Make.defs:
##########
@@ -64,15 +64,17 @@ ifeq ($(CONFIG_SCHED_THREAD_LOCAL),y)
 endif
 
 ifeq ($(CONFIG_SCHED_BACKTRACE),y)

Review Comment:
   Done



##########
arch/arm/src/common/arm_backtrace_unwind.c:
##########
@@ -0,0 +1,680 @@
+/****************************************************************************
+ * arch/arm/src/common/arm_backtrace_unwind.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 <arch/elf.h>
+
+#include "sched/sched.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum regs
+{
+#ifdef CONFIG_ARM_THUMB
+  FP = 7,
+#else
+  FP = 11,
+#endif /* CONFIG_ARM_THUMB */
+  SP = 13,
+  LR = 14,
+  PC = 15
+};
+
+/****************************************************************************
+ * Private Data Types
+ ****************************************************************************/
+
+struct unwind_frame_s
+{
+  unsigned long fp;
+  unsigned long sp;
+  unsigned long lr;
+  unsigned long pc;
+
+  /* address of the LR value on the stack */
+
+  unsigned long *lr_addr;
+
+  /* highest value of sp allowed */
+
+  unsigned long stack_top;
+};
+
+struct unwind_ctrl_s
+{
+  unsigned long        vrs[16];   /* virtual register set */
+  const unsigned long *insn;      /* pointer to the current instructions word */
+  unsigned long        stack_top; /* highest value of sp allowed */
+  unsigned long       *lr_addr;   /* address of LR value on the stack */
+  int                  entries;   /* number of entries left to interpret */
+  int                  byte;      /* current byte number in the instructions word */
+
+  /* 1 : check for stack overflow for each register pop.
+   * 0 : save overhead if there is plenty of stack remaining.
+   */
+
+  int check_each_pop;
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Convert a prel31 symbol to an absolute address */
+
+#define prel31_to_addr(ptr)  \
+  ({  \
+  /* sign-extend to 32 bits */  \
+  long offset = (((long)*(ptr)) << 1) >> 1;  \
+  (unsigned long)(ptr) + offset;  \
+  })
+
+/****************************************************************************
+ * Name: search_index
+ *
+ * Description:
+ *  Binary search in the unwind index. The entries are
+ *  guaranteed to be sorted in ascending order by the linker.
+ *
+ *  start    = first entry
+ *  origin   = first entry with positive offset
+ *             (or stop if there is no such entry)
+ *  stop - 1 = last entry
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static const struct __EIT_entry *
+search_index(unsigned long addr, const struct __EIT_entry *start,
+             const struct __EIT_entry *origin,
+             const struct __EIT_entry *stop)
+{
+  unsigned long addr_prel31;
+
+  /* only search in the section with the matching sign. This way the
+   * prel31 numbers can be compared as unsigned longs.
+   */
+
+  if (addr < (unsigned long)start)
+    {
+      /* negative offsets: [start; origin) */
+
+      stop = origin;
+    }
+  else
+    {
+      /* positive offsets: [origin; stop) */
+
+      start = origin;
+    }
+
+  /* prel31 for address relavive to start */
+
+  addr_prel31 = (addr - (unsigned long)start) & 0x7fffffff;
+
+  while (start < stop - 1)
+    {
+      const struct __EIT_entry *mid = start + ((stop - start) >> 1);
+
+      /* As addr_prel31 is relative to start an offset is needed to
+       * make it relative to mid.
+       */
+
+      if (addr_prel31 -
+          ((unsigned long)mid - (unsigned long)start) < mid->fnoffset)
+        {
+          stop = mid;
+        }
+      else
+        {
+          /* keep addr_prel31 relative to start */
+
+          addr_prel31 -= ((unsigned long)mid - (unsigned long)start);
+          start = mid;
+        }
+    }
+
+  return (start->fnoffset <= addr_prel31) ? start : NULL;
+}
+
+nosanitize_address
+static const struct __EIT_entry *
+unwind_find_origin(const struct __EIT_entry *start,
+                   const struct __EIT_entry *stop)
+{
+  const struct __EIT_entry *mid;
+
+  while (start < stop)
+    {
+      mid = start + ((stop - start) >> 1);
+
+      if (mid->fnoffset >= 0x40000000)
+        {
+          /* negative offset */
+
+          start = mid + 1;
+        }
+      else
+        {
+          /* positive offset */
+
+          stop = mid;
+        }
+    }
+
+  return stop;
+}
+
+nosanitize_address
+static const struct __EIT_entry *unwind_find_entry(unsigned long addr)
+{
+  /* main unwind table */
+
+  return search_index(addr, __exidx_start,
+                      unwind_find_origin(__exidx_start, __exidx_end),
+                      __exidx_end);
+}
+
+nosanitize_address
+static unsigned long unwind_get_byte(struct unwind_ctrl_s *ctrl)
+{
+  unsigned long ret;
+
+  if (ctrl->entries <= 0)
+    {
+      return 0;
+    }
+
+  ret = (*ctrl->insn >> (ctrl->byte * 8)) & 0xff;
+
+  if (ctrl->byte == 0)
+    {
+      ctrl->insn++;
+      ctrl->entries--;
+      ctrl->byte = 3;
+    }
+  else
+    {
+      ctrl->byte--;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Before poping a register check whether it is feasible or not
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static int unwind_pop_register(struct unwind_ctrl_s *ctrl,
+                               unsigned long **vsp, unsigned int reg)
+{
+  if (ctrl->check_each_pop)
+    {
+      if (*vsp >= (unsigned long *)ctrl->stack_top)
+        {
+          return -1;
+        }
+    }
+
+  /* Use READ_ONCE_NOCHECK here to avoid this memory access
+   * from being tracked by KASAN.
+   */
+
+  ctrl->vrs[reg] = *(*vsp);
+  if (reg == LR)
+    {
+      ctrl->lr_addr = *vsp;
+    }
+
+  (*vsp)++;
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Helper functions to execute the instructions
+ *
+ ****************************************************************************/
+
+nosanitize_address static int
+unwind_exec_pop_subset_r4_to_r13(struct unwind_ctrl_s *ctrl,
+                                 unsigned long mask)
+{
+  unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+  int load_sp;
+  int reg = 4;
+
+  load_sp = mask & (1 << (13 - 4));
+  while (mask)
+    {
+      if ((mask & 1) && unwind_pop_register(ctrl, &vsp, reg))
+        {
+          return -1;
+        }
+
+      mask >>= 1;
+      reg++;
+    }
+
+  if (!load_sp)
+    {
+      ctrl->vrs[SP] = (unsigned long)vsp;
+    }
+
+  return 0;
+}
+
+nosanitize_address
+static int unwind_exec_pop_r4_to_rn(struct unwind_ctrl_s *ctrl,
+                                    unsigned long content)
+{
+  unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+  int reg;
+
+  /* pop R4-R[4+bbb] */
+
+  for (reg = 4; reg <= 4 + (content & 7); reg++)
+    {
+      if (unwind_pop_register(ctrl, &vsp, reg))
+        {
+          return -1;
+        }
+    }
+
+  if ((content & 0x8) && unwind_pop_register(ctrl, &vsp, 14))
+    {
+      return -1;
+    }
+
+  ctrl->vrs[SP] = (unsigned long)vsp;
+
+  return 0;
+}
+
+nosanitize_address
+static int unwind_exec_pop_subset_r0_to_r3(struct unwind_ctrl_s *ctrl,
+                                           unsigned long mask)
+{
+  unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+  int reg = 0;
+
+  /* pop R0-R3 according to mask */
+
+  while (mask)
+    {
+      if ((mask & 1) && unwind_pop_register(ctrl, &vsp, reg))
+        {
+          return -1;
+        }
+
+      mask >>= 1;
+      reg++;
+    }
+
+  ctrl->vrs[SP] = (unsigned long)vsp;
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Execute the current unwind instruction
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static int unwind_exec_content(struct unwind_ctrl_s *ctrl)
+{
+  unsigned long content = unwind_get_byte(ctrl);
+  int ret = 0;
+
+  if ((content & 0xc0) == 0x00)
+    {
+      ctrl->vrs[SP] += ((content & 0x3f) << 2) + 4;
+    }
+  else if ((content & 0xc0) == 0x40)
+    {
+      ctrl->vrs[SP] -= ((content & 0x3f) << 2) + 4;
+    }
+  else if ((content & 0xf0) == 0x80)
+    {
+      unsigned long mask;
+
+      content = (content << 8) | unwind_get_byte(ctrl);
+      mask = content & 0x0fff;
+      ret = (mask == 0) ? -1 :
+            unwind_exec_pop_subset_r4_to_r13(ctrl, mask);
+    }
+  else if ((content & 0xf0) == 0x90 &&
+           (content & 0x0d) != 0x0d)
+    {
+      ctrl->vrs[SP] = ctrl->vrs[content & 0x0f];
+    }
+  else if ((content & 0xf0) == 0xa0)
+    {
+      ret = unwind_exec_pop_r4_to_rn(ctrl, content);
+    }
+  else if (content == 0xb0)
+    {
+      if (ctrl->vrs[PC] == 0)
+        {
+          ctrl->vrs[PC] = ctrl->vrs[LR];
+        }
+
+      /* no further processing */
+
+      ctrl->entries = 0;
+    }
+  else if (content == 0xb1)
+    {
+      unsigned long mask = unwind_get_byte(ctrl);
+
+      if (mask == 0 || mask & 0xf0)
+        {
+          ret = -1;
+        }
+      else
+        {
+          ret = unwind_exec_pop_subset_r0_to_r3(ctrl, mask);
+        }
+    }
+  else if (content == 0xb2)
+    {
+      unsigned long uleb128 = unwind_get_byte(ctrl);
+
+      ctrl->vrs[SP] += 0x204 + (uleb128 << 2);
+    }
+  else
+    {
+      ret = -1;
+    }
+
+  return ret;
+}
+
+nosanitize_address
+int unwind_frame(struct unwind_frame_s *frame)
+{
+  const struct __EIT_entry *entry;
+  struct unwind_ctrl_s ctrl;
+
+  entry = unwind_find_entry(frame->pc);
+  if (!entry || entry->content == 1)
+    {
+      return -1;
+    }
+
+  ctrl.vrs[FP] = frame->fp;
+  ctrl.vrs[SP] = frame->sp;
+  ctrl.vrs[LR] = frame->lr;
+  ctrl.vrs[PC] = 0;
+  ctrl.stack_top = frame->stack_top;
+
+  if (frame->pc == prel31_to_addr(&entry->fnoffset))
+    {
+      /* Unwinding is tricky when we're halfway through the prologue,
+       * since the stack frame that the unwinder expects may not be
+       * fully set up yet. However, one thing we do know for sure is
+       * that if we are unwinding from the very first instruction of
+       * a function, we are still effectively in the stack frame of
+       * the caller, and the unwind info has no relevance yet.
+       */
+
+      if (frame->pc == frame->lr)
+        {
+          return -1;
+        }
+
+      frame->pc = frame->lr;
+
+      return 0;
+    }
+  else if ((entry->content & 0x80000000) == 0)
+    {
+      /* prel31 to the unwind table */
+
+      ctrl.insn = (unsigned long *)prel31_to_addr(&entry->content);
+    }
+  else if ((entry->content & 0xff000000) == 0x80000000)
+    {
+      /* only personality routine 0 supported in the index */
+
+      ctrl.insn = &entry->content;
+    }
+  else
+    {
+      return -1;
+    }
+
+  /* check the personality routine */
+
+  if ((*ctrl.insn & 0xff000000) == 0x80000000)
+    {
+      ctrl.byte = 2;
+      ctrl.entries = 1;
+    }
+  else if ((*ctrl.insn & 0xff000000) == 0x81000000)
+    {
+      ctrl.byte = 1;
+      ctrl.entries = 1 + ((*ctrl.insn & 0x00ff0000) >> 16);
+    }
+  else
+    {
+      return -1;
+    }
+
+  ctrl.check_each_pop = 0;
+
+  while (ctrl.entries > 0)
+    {
+      int urc;
+
+      if ((ctrl.stack_top - ctrl.vrs[SP]) < sizeof(ctrl.vrs))
+        {
+          ctrl.check_each_pop = 1;
+        }
+
+      urc = unwind_exec_content(&ctrl);
+      if (urc < 0)
+        {
+          return urc;
+        }
+
+      if (ctrl.vrs[SP] < frame->sp ||
+          ctrl.vrs[SP] > ctrl.stack_top)
+        {
+          return -1;
+        }
+    }
+
+  if (ctrl.vrs[PC] == 0)
+    {
+      ctrl.vrs[PC] = ctrl.vrs[LR];
+    }
+
+  /* check for infinite loop */
+
+  if (frame->pc == ctrl.vrs[PC] && frame->sp == ctrl.vrs[SP])
+    {
+      return -1;
+    }
+
+  frame->fp = ctrl.vrs[FP];
+  frame->sp = ctrl.vrs[SP];
+  frame->lr = ctrl.vrs[LR];
+  frame->pc = ctrl.vrs[PC];
+  frame->lr_addr = ctrl.lr_addr;
+
+  return 0;
+}
+
+nosanitize_address
+static int backtrace_unwind(struct unwind_frame_s *frame,
+                            void **buffer, int size, int *skip)
+{
+  int cnt = 0;
+
+  if (frame->pc && cnt < size && (*skip)-- <= 0)
+    {
+      buffer[cnt++] = (FAR void *)((frame->pc & ~1) - 2);
+    }
+
+  if (frame->lr && cnt < size && (*skip)-- <= 0)
+    {
+      buffer[cnt++] = (FAR void *)((frame->lr & ~1) - 2);
+    }
+
+  while (cnt < size)
+    {
+      if (unwind_frame(frame) < 0 || frame->pc == 0)
+        {
+          break;
+        }
+
+      if ((*skip)-- <= 0)
+        {
+          frame->pc = (frame->pc & ~1) - 2;
+
+          if (cnt == 0 || (FAR void *)frame->pc != buffer[cnt - 1])
+            {
+              buffer[cnt++] = (FAR void *)frame->pc;
+            }
+        }
+    }
+
+  return cnt > 0 ? cnt : 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_backtrace
+ *
+ * Description:
+ *  up_backtrace()  returns  a backtrace for the TCB, in the array
+ *  pointed to by buffer.  A backtrace is the series of currently active
+ *  function calls for the program.  Each item in the array pointed to by
+ *  buffer is of type void *, and is the return address from the
+ *  corresponding stack frame.  The size argument specifies the maximum
+ *  number of addresses that can be stored in buffer.   If  the backtrace is
+ *  larger than size, then the addresses corresponding to the size most
+ *  recent function calls are returned; to obtain the complete backtrace,
+ *  make sure that buffer and size are large enough.
+ *
+ * Input Parameters:
+ *   tcb    - Address of the task's TCB
+ *   buffer - Return address from the corresponding stack frame
+ *   size   - Maximum number of addresses that can be stored in buffer
+ *   skip   - number of addresses to be skipped
+ *
+ * Returned Value:
+ *   up_backtrace() returns the number of addresses returned in buffer
+ *
+ ****************************************************************************/
+
+nosanitize_address
+int up_backtrace(struct tcb_s *tcb,
+                 void **buffer, int size, int skip)
+{
+  struct tcb_s *rtcb = running_task();
+  struct unwind_frame_s frame;
+  irqstate_t flags;
+  int ret;
+
+  if (size <= 0 || !buffer)
+    {
+      return 0;
+    }
+
+  if (tcb == NULL || tcb == rtcb)
+    {
+      frame.fp = (unsigned long)__builtin_frame_address(0);
+      frame.lr = (unsigned long)__builtin_return_address(0);
+      frame.pc = (unsigned long)&up_backtrace;
+      frame.sp = frame.fp;
+      frame.stack_top = (unsigned long)rtcb->stack_base_ptr +
+                                       rtcb->adj_stack_size;

Review Comment:
   Done



##########
arch/arm/src/common/arm_backtrace_unwind.c:
##########
@@ -0,0 +1,680 @@
+/****************************************************************************
+ * arch/arm/src/common/arm_backtrace_unwind.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 <arch/elf.h>
+
+#include "sched/sched.h"
+#include "arm_internal.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum regs
+{
+#ifdef CONFIG_ARM_THUMB
+  FP = 7,
+#else
+  FP = 11,
+#endif /* CONFIG_ARM_THUMB */
+  SP = 13,
+  LR = 14,
+  PC = 15
+};
+
+/****************************************************************************
+ * Private Data Types
+ ****************************************************************************/
+
+struct unwind_frame_s
+{
+  unsigned long fp;
+  unsigned long sp;
+  unsigned long lr;
+  unsigned long pc;
+
+  /* address of the LR value on the stack */
+
+  unsigned long *lr_addr;
+
+  /* highest value of sp allowed */
+
+  unsigned long stack_top;
+};
+
+struct unwind_ctrl_s
+{
+  unsigned long        vrs[16];   /* virtual register set */
+  const unsigned long *insn;      /* pointer to the current instructions word */
+  unsigned long        stack_top; /* highest value of sp allowed */
+  unsigned long       *lr_addr;   /* address of LR value on the stack */
+  int                  entries;   /* number of entries left to interpret */
+  int                  byte;      /* current byte number in the instructions word */
+
+  /* 1 : check for stack overflow for each register pop.
+   * 0 : save overhead if there is plenty of stack remaining.
+   */
+
+  int check_each_pop;
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Convert a prel31 symbol to an absolute address */
+
+#define prel31_to_addr(ptr)  \
+  ({  \
+  /* sign-extend to 32 bits */  \
+  long offset = (((long)*(ptr)) << 1) >> 1;  \
+  (unsigned long)(ptr) + offset;  \
+  })
+
+/****************************************************************************
+ * Name: search_index
+ *
+ * Description:
+ *  Binary search in the unwind index. The entries are
+ *  guaranteed to be sorted in ascending order by the linker.
+ *
+ *  start    = first entry
+ *  origin   = first entry with positive offset
+ *             (or stop if there is no such entry)
+ *  stop - 1 = last entry
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static const struct __EIT_entry *
+search_index(unsigned long addr, const struct __EIT_entry *start,
+             const struct __EIT_entry *origin,
+             const struct __EIT_entry *stop)
+{
+  unsigned long addr_prel31;
+
+  /* only search in the section with the matching sign. This way the
+   * prel31 numbers can be compared as unsigned longs.
+   */
+
+  if (addr < (unsigned long)start)
+    {
+      /* negative offsets: [start; origin) */
+
+      stop = origin;
+    }
+  else
+    {
+      /* positive offsets: [origin; stop) */
+
+      start = origin;
+    }
+
+  /* prel31 for address relavive to start */
+
+  addr_prel31 = (addr - (unsigned long)start) & 0x7fffffff;
+
+  while (start < stop - 1)
+    {
+      const struct __EIT_entry *mid = start + ((stop - start) >> 1);
+
+      /* As addr_prel31 is relative to start an offset is needed to
+       * make it relative to mid.
+       */
+
+      if (addr_prel31 -
+          ((unsigned long)mid - (unsigned long)start) < mid->fnoffset)
+        {
+          stop = mid;
+        }
+      else
+        {
+          /* keep addr_prel31 relative to start */
+
+          addr_prel31 -= ((unsigned long)mid - (unsigned long)start);
+          start = mid;
+        }
+    }
+
+  return (start->fnoffset <= addr_prel31) ? start : NULL;
+}
+
+nosanitize_address
+static const struct __EIT_entry *
+unwind_find_origin(const struct __EIT_entry *start,
+                   const struct __EIT_entry *stop)
+{
+  const struct __EIT_entry *mid;
+
+  while (start < stop)
+    {
+      mid = start + ((stop - start) >> 1);
+
+      if (mid->fnoffset >= 0x40000000)
+        {
+          /* negative offset */
+
+          start = mid + 1;
+        }
+      else
+        {
+          /* positive offset */
+
+          stop = mid;
+        }
+    }
+
+  return stop;
+}
+
+nosanitize_address
+static const struct __EIT_entry *unwind_find_entry(unsigned long addr)
+{
+  /* main unwind table */
+
+  return search_index(addr, __exidx_start,
+                      unwind_find_origin(__exidx_start, __exidx_end),
+                      __exidx_end);
+}
+
+nosanitize_address
+static unsigned long unwind_get_byte(struct unwind_ctrl_s *ctrl)
+{
+  unsigned long ret;
+
+  if (ctrl->entries <= 0)
+    {
+      return 0;
+    }
+
+  ret = (*ctrl->insn >> (ctrl->byte * 8)) & 0xff;
+
+  if (ctrl->byte == 0)
+    {
+      ctrl->insn++;
+      ctrl->entries--;
+      ctrl->byte = 3;
+    }
+  else
+    {
+      ctrl->byte--;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Before poping a register check whether it is feasible or not
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static int unwind_pop_register(struct unwind_ctrl_s *ctrl,
+                               unsigned long **vsp, unsigned int reg)
+{
+  if (ctrl->check_each_pop)
+    {
+      if (*vsp >= (unsigned long *)ctrl->stack_top)
+        {
+          return -1;
+        }
+    }
+
+  /* Use READ_ONCE_NOCHECK here to avoid this memory access
+   * from being tracked by KASAN.
+   */
+
+  ctrl->vrs[reg] = *(*vsp);
+  if (reg == LR)
+    {
+      ctrl->lr_addr = *vsp;
+    }
+
+  (*vsp)++;
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Helper functions to execute the instructions
+ *
+ ****************************************************************************/
+
+nosanitize_address static int
+unwind_exec_pop_subset_r4_to_r13(struct unwind_ctrl_s *ctrl,
+                                 unsigned long mask)
+{
+  unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+  int load_sp;
+  int reg = 4;
+
+  load_sp = mask & (1 << (13 - 4));
+  while (mask)
+    {
+      if ((mask & 1) && unwind_pop_register(ctrl, &vsp, reg))
+        {
+          return -1;
+        }
+
+      mask >>= 1;
+      reg++;
+    }
+
+  if (!load_sp)
+    {
+      ctrl->vrs[SP] = (unsigned long)vsp;
+    }
+
+  return 0;
+}
+
+nosanitize_address
+static int unwind_exec_pop_r4_to_rn(struct unwind_ctrl_s *ctrl,
+                                    unsigned long content)
+{
+  unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+  int reg;
+
+  /* pop R4-R[4+bbb] */
+
+  for (reg = 4; reg <= 4 + (content & 7); reg++)
+    {
+      if (unwind_pop_register(ctrl, &vsp, reg))
+        {
+          return -1;
+        }
+    }
+
+  if ((content & 0x8) && unwind_pop_register(ctrl, &vsp, 14))
+    {
+      return -1;
+    }
+
+  ctrl->vrs[SP] = (unsigned long)vsp;
+
+  return 0;
+}
+
+nosanitize_address
+static int unwind_exec_pop_subset_r0_to_r3(struct unwind_ctrl_s *ctrl,
+                                           unsigned long mask)
+{
+  unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+  int reg = 0;
+
+  /* pop R0-R3 according to mask */
+
+  while (mask)
+    {
+      if ((mask & 1) && unwind_pop_register(ctrl, &vsp, reg))
+        {
+          return -1;
+        }
+
+      mask >>= 1;
+      reg++;
+    }
+
+  ctrl->vrs[SP] = (unsigned long)vsp;
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: unwind_pop_register
+ *
+ * Description:
+ *  Execute the current unwind instruction
+ *
+ ****************************************************************************/
+
+nosanitize_address
+static int unwind_exec_content(struct unwind_ctrl_s *ctrl)
+{
+  unsigned long content = unwind_get_byte(ctrl);
+  int ret = 0;
+
+  if ((content & 0xc0) == 0x00)
+    {
+      ctrl->vrs[SP] += ((content & 0x3f) << 2) + 4;
+    }
+  else if ((content & 0xc0) == 0x40)
+    {
+      ctrl->vrs[SP] -= ((content & 0x3f) << 2) + 4;
+    }
+  else if ((content & 0xf0) == 0x80)
+    {
+      unsigned long mask;
+
+      content = (content << 8) | unwind_get_byte(ctrl);
+      mask = content & 0x0fff;
+      ret = (mask == 0) ? -1 :
+            unwind_exec_pop_subset_r4_to_r13(ctrl, mask);
+    }
+  else if ((content & 0xf0) == 0x90 &&
+           (content & 0x0d) != 0x0d)
+    {
+      ctrl->vrs[SP] = ctrl->vrs[content & 0x0f];
+    }
+  else if ((content & 0xf0) == 0xa0)
+    {
+      ret = unwind_exec_pop_r4_to_rn(ctrl, content);
+    }
+  else if (content == 0xb0)
+    {
+      if (ctrl->vrs[PC] == 0)
+        {
+          ctrl->vrs[PC] = ctrl->vrs[LR];
+        }
+
+      /* no further processing */
+
+      ctrl->entries = 0;
+    }
+  else if (content == 0xb1)
+    {
+      unsigned long mask = unwind_get_byte(ctrl);
+
+      if (mask == 0 || mask & 0xf0)
+        {
+          ret = -1;
+        }
+      else
+        {
+          ret = unwind_exec_pop_subset_r0_to_r3(ctrl, mask);
+        }
+    }
+  else if (content == 0xb2)
+    {
+      unsigned long uleb128 = unwind_get_byte(ctrl);
+
+      ctrl->vrs[SP] += 0x204 + (uleb128 << 2);
+    }
+  else
+    {
+      ret = -1;
+    }
+
+  return ret;
+}
+
+nosanitize_address
+int unwind_frame(struct unwind_frame_s *frame)
+{
+  const struct __EIT_entry *entry;

Review Comment:
   Done



-- 
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-unsubscribe@nuttx.apache.org

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


[GitHub] [incubator-nuttx] xiaoxiang781216 merged pull request #7260: arm/backtrace: add support for EHABI(Exception Handling ABI) stack unwinder

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 merged PR #7260:
URL: https://github.com/apache/incubator-nuttx/pull/7260


-- 
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-unsubscribe@nuttx.apache.org

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