diff --git a/arch/arm/src/armv6-m/arm_backtrace.c b/arch/arm/src/armv6-m/arm_backtrace.c deleted file mode 100644 index ad03627c3c..0000000000 --- a/arch/arm/src/armv6-m/arm_backtrace.c +++ /dev/null @@ -1,295 +0,0 @@ -/**************************************************************************** - * arch/arm/src/armv6-m/arm_backtrace.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 - -#include - -#include "sched/sched.h" - -#include "arm_internal.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* Macro and definitions for simple decoding of instuctions. - * To check an instruction, it is ANDed with the IMASK_ and - * the result is compared with the IOP_. The macro INSTR_IS - * does this and returns !0 to indicate a match. - */ - -#define INSTR_IS(i, o) (((i) & (IMASK_##o)) == (IOP_##o)) - -#define IMASK_T_BLX 0xff80 /* blx */ -#define IOP_T_BLX 0x4780 - -#define IMASK_T_BL 0xf800 /* blx */ -#define IOP_T_BL 0xf000 - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static FAR void **g_backtrace_code_regions; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: in_code_region - * - * Description: - * in_code_region() check if the program counter is in the program - * section, program counter should always be within the view of executable - * sections. - * - * Input Parameters: - * pc - Program counter address - * - * Returned Value: - * A boolean value: true the counter is vaild - * - ****************************************************************************/ - -#ifdef CONFIG_MM_KASAN -__attribute__((no_sanitize_address)) -#endif -static bool in_code_region(FAR void *pc) -{ - int i = 0; - - if ((uintptr_t)pc >= (uintptr_t)_START_TEXT && - (uintptr_t)pc < (uintptr_t)_END_TEXT) - { - return true; - } - - if (g_backtrace_code_regions) - { - while (g_backtrace_code_regions[i] && - (g_backtrace_code_regions[i] != - g_backtrace_code_regions[i + 1])) - { - if (g_backtrace_code_regions[i] <= pc && - g_backtrace_code_regions[i + 1] > pc) - { - return true; - } - - i += 2; - } - } - - return false; -} - -/**************************************************************************** - * Name: backtrace_branch - * - * Description: - * backtrace() parsing the return address through branch instruction - * - ****************************************************************************/ - -#ifdef CONFIG_MM_KASAN -__attribute__((no_sanitize_address)) -#endif -static int backtrace_branch(FAR void *limit, FAR void *sp, - FAR void **buffer, int size) -{ - uint16_t ins16; - uint32_t addr; - int i = 0; - - for (; i < size && sp < limit; sp += sizeof(uint32_t)) - { - addr = *(FAR uint32_t *)sp; - if (!in_code_region(addr)) - { - continue; - } - - addr = (addr & ~1) - 2; - ins16 = *(FAR uint16_t *)addr; - if (INSTR_IS(ins16, T_BLX)) - { - buffer[i++] = addr; - } - - /* BL Instruction - * OFFSET: 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 - * VALUE : 1 1 1 1 0 - - - - - - - - - - - - * OFFSET: 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 - * VALUE : 1 1 - 1 - - - - - - - - - - - - - */ - - else if ((ins16 & 0xd000) == 0xd000) - { - addr -= 2; - ins16 = *(FAR uint16_t *)addr; - if (INSTR_IS(ins16, T_BL)) - { - buffer[i++] = addr; - } - } - } - - return i; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: arm_backtrace_init_code_regions - * - * Description: - * The up call arm_backtrace_init_code_regions() will set the start - * and end addresses of the customized program sections, this method - * will help the different boards to configure the current text - * sections for some complicate platfroms - * - * Input Parameters: - * regions The start and end address of the text segment - * This interface supports the input of multiple - * groups of sections, Each set of the sections - * must be a pair, the end of the area must specify - * two NULL porint, e.g : - * - * static void *g_code_regions[] = - * { - * _START_TEXT, _END_TEXT, - * _START2_TEXT, _END2_TEXT, - * _START3_TEXT, _END3_TEXT, - * NULL, NULL, - * }; - * - * arm_backtrace_init_code_regions(g_code_regions); - * - ****************************************************************************/ - -#ifdef CONFIG_MM_KASAN -__attribute__((no_sanitize_address)) -#endif -void arm_backtrace_init_code_regions(FAR void **regions) -{ - g_backtrace_code_regions = regions; -} - -/**************************************************************************** - * 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 - * - * Returned Value: - * up_backtrace() returns the number of addresses returned in buffer - * - ****************************************************************************/ - -#ifdef CONFIG_MM_KASAN -__attribute__((no_sanitize_address)) -#endif -int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size) -{ - FAR struct tcb_s *rtcb = running_task(); - irqstate_t flags; - FAR void *sp; - int ret; - - if (size <= 0 || !buffer) - { - return 0; - } - - if (tcb == NULL) - { - tcb = rtcb; - } - - if (tcb == rtcb) - { - sp = (FAR void *)up_getsp(); - if (up_interrupt_context()) - { -#if CONFIG_ARCH_INTERRUPTSTACK > 7 - ret = backtrace_branch( -# ifdef CONFIG_SMP - (uint32_t)arm_intstack_alloc() -# else - (uint32_t)&g_intstackalloc -# endif - + (CONFIG_ARCH_INTERRUPTSTACK & ~7), sp, - buffer, size); - if (ret < size) - { - sp = (FAR void *)CURRENT_REGS[REG_SP]; - ret += backtrace_branch(rtcb->stack_base_ptr + - rtcb->adj_stack_size, sp, - &buffer[ret], size - ret); - } -#else - sp = (FAR void *)CURRENT_REGS[REG_SP]; - ret = backtrace_branch(rtcb->stack_base_ptr + - rtcb->adj_stack_size, sp, - buffer, size); -#endif - } - else - { - ret = backtrace_branch(rtcb->stack_base_ptr + - rtcb->adj_stack_size, sp, - buffer, size); - } - } - else - { - flags = enter_critical_section(); - - ret = backtrace_branch(tcb->stack_base_ptr + - tcb->adj_stack_size, - (FAR void *)tcb->xcp.regs[REG_SP], - buffer, size); - - leave_critical_section(flags); - } - - return ret; -} diff --git a/arch/arm/src/armv7-a/arm_backtrace.c b/arch/arm/src/armv7-a/arm_backtrace.c deleted file mode 100644 index 8c505a59ba..0000000000 --- a/arch/arm/src/armv7-a/arm_backtrace.c +++ /dev/null @@ -1,162 +0,0 @@ -/**************************************************************************** - * arch/arm/src/armv7-a/arm_backtrace.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 -#include -#include - -#include "sched/sched.h" - -#include "arm_internal.h" - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: backtrace - * - * Description: - * backtrace() parsing the return address through frame pointer - * - ****************************************************************************/ - -static int backtrace(FAR uintptr_t *base, FAR uintptr_t *limit, - FAR uintptr_t *fp, FAR uintptr_t *pc, - FAR void **buffer, int size) -{ - int i = 0; - - if (pc) - { - buffer[i++] = pc; - } - - for (; i < size; fp = (FAR uintptr_t *)*(fp - 1), i++) - { - if (fp > limit || fp < base || *fp == 0) - { - break; - } - - buffer[i] = (FAR void *)*fp; - } - - return i; -} - -/**************************************************************************** - * 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 - * - * Returned Value: - * up_backtrace() returns the number of addresses returned in buffer - * - ****************************************************************************/ - -int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size) -{ - FAR struct tcb_s *rtcb = running_task(); -#if CONFIG_ARCH_INTERRUPTSTACK > 7 - FAR void *istacklimit; -#endif - irqstate_t flags; - int ret; - - if (size <= 0 || !buffer) - { - return 0; - } - - if (tcb == NULL || tcb == rtcb) - { - if (up_interrupt_context()) - { -#if CONFIG_ARCH_INTERRUPTSTACK > 7 -# ifdef CONFIG_SMP - istacklimit = arm_intstack_top(); -# else - istacklimit = &g_intstacktop; -# endif /* CONFIG_SMP */ - ret = backtrace(istacklimit - (CONFIG_ARCH_INTERRUPTSTACK & ~7), - istacklimit, - (FAR void *)__builtin_frame_address(0), - NULL, buffer, size); -#else - ret = backtrace(rtcb->stack_base_ptr, - rtcb->stack_base_ptr + rtcb->adj_stack_size, - (FAR void *)__builtin_frame_address(0), - NULL, buffer, size); -#endif /* CONFIG_ARCH_INTERRUPTSTACK > 7 */ - if (ret < size) - { - ret += backtrace(rtcb->stack_base_ptr, - rtcb->stack_base_ptr + rtcb->adj_stack_size, - (FAR void *)CURRENT_REGS[REG_FP], - (FAR void *)CURRENT_REGS[REG_PC], - &buffer[ret], size - ret); - } - } - else - { - ret = backtrace(rtcb->stack_base_ptr, - rtcb->stack_base_ptr + rtcb->adj_stack_size, - (FAR void *)__builtin_frame_address(0), - NULL, buffer, size); - } - } - else - { - flags = enter_critical_section(); - - ret = backtrace(tcb->stack_base_ptr, - tcb->stack_base_ptr + tcb->adj_stack_size, - (FAR void *)tcb->xcp.regs[REG_FP], - (FAR void *)tcb->xcp.regs[REG_PC], - buffer, size); - - leave_critical_section(flags); - } - - return ret; -} diff --git a/arch/arm/src/armv7-m/arm_backtrace.c b/arch/arm/src/armv7-m/arm_backtrace.c deleted file mode 100644 index fdea7d23da..0000000000 --- a/arch/arm/src/armv7-m/arm_backtrace.c +++ /dev/null @@ -1,295 +0,0 @@ -/**************************************************************************** - * arch/arm/src/armv7-m/arm_backtrace.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 - -#include - -#include "sched/sched.h" - -#include "arm_internal.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* Macro and definitions for simple decoding of instuctions. - * To check an instruction, it is ANDed with the IMASK_ and - * the result is compared with the IOP_. The macro INSTR_IS - * does this and returns !0 to indicate a match. - */ - -#define INSTR_IS(i, o) (((i) & (IMASK_##o)) == (IOP_##o)) - -#define IMASK_T_BLX 0xff80 /* blx */ -#define IOP_T_BLX 0x4780 - -#define IMASK_T_BL 0xf800 /* blx */ -#define IOP_T_BL 0xf000 - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static FAR void **g_backtrace_code_regions; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: in_code_region - * - * Description: - * in_code_region() check if the program counter is in the program - * section, program counter should always be within the view of executable - * sections. - * - * Input Parameters: - * pc - Program counter address - * - * Returned Value: - * A boolean value: true the counter is vaild - * - ****************************************************************************/ - -#ifdef CONFIG_MM_KASAN -__attribute__((no_sanitize_address)) -#endif -static bool in_code_region(FAR void *pc) -{ - int i = 0; - - if ((uintptr_t)pc >= (uintptr_t)_START_TEXT && - (uintptr_t)pc < (uintptr_t)_END_TEXT) - { - return true; - } - - if (g_backtrace_code_regions) - { - while (g_backtrace_code_regions[i] && - (g_backtrace_code_regions[i] != - g_backtrace_code_regions[i + 1])) - { - if (g_backtrace_code_regions[i] <= pc && - g_backtrace_code_regions[i + 1] > pc) - { - return true; - } - - i += 2; - } - } - - return false; -} - -/**************************************************************************** - * Name: backtrace_branch - * - * Description: - * backtrace() parsing the return address through branch instruction - * - ****************************************************************************/ - -#ifdef CONFIG_MM_KASAN -__attribute__((no_sanitize_address)) -#endif -static int backtrace_branch(FAR void *limit, FAR void *sp, - FAR void **buffer, int size) -{ - uint16_t ins16; - uint32_t addr; - int i = 0; - - for (; i < size && sp < limit; sp += sizeof(uint32_t)) - { - addr = *(FAR uint32_t *)sp; - if (!in_code_region(addr)) - { - continue; - } - - addr = (addr & ~1) - 2; - ins16 = *(FAR uint16_t *)addr; - if (INSTR_IS(ins16, T_BLX)) - { - buffer[i++] = addr; - } - - /* BL Instruction - * OFFSET: 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 - * VALUE : 1 1 1 1 0 - - - - - - - - - - - - * OFFSET: 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 - * VALUE : 1 1 - 1 - - - - - - - - - - - - - */ - - else if ((ins16 & 0xd000) == 0xd000) - { - addr -= 2; - ins16 = *(FAR uint16_t *)addr; - if (INSTR_IS(ins16, T_BL)) - { - buffer[i++] = addr; - } - } - } - - return i; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: arm_backtrace_init_code_regions - * - * Description: - * The up call arm_backtrace_init_code_regions() will set the start - * and end addresses of the customized program sections, this method - * will help the different boards to configure the current text - * sections for some complicate platfroms - * - * Input Parameters: - * regions The start and end address of the text segment - * This interface supports the input of multiple - * groups of sections, Each set of the sections - * must be a pair, the end of the area must specify - * two NULL porint, e.g : - * - * static void *g_code_regions[] = - * { - * _START_TEXT, _END_TEXT, - * _START2_TEXT, _END2_TEXT, - * _START3_TEXT, _END3_TEXT, - * NULL, NULL, - * }; - * - * arm_backtrace_init_code_regions(g_code_regions); - * - ****************************************************************************/ - -#ifdef CONFIG_MM_KASAN -__attribute__((no_sanitize_address)) -#endif -void arm_backtrace_init_code_regions(FAR void **regions) -{ - g_backtrace_code_regions = regions; -} - -/**************************************************************************** - * 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 - * - * Returned Value: - * up_backtrace() returns the number of addresses returned in buffer - * - ****************************************************************************/ - -#ifdef CONFIG_MM_KASAN -__attribute__((no_sanitize_address)) -#endif -int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size) -{ - FAR struct tcb_s *rtcb = running_task(); - irqstate_t flags; - FAR void *sp; - int ret; - - if (size <= 0 || !buffer) - { - return 0; - } - - if (tcb == NULL) - { - tcb = rtcb; - } - - if (tcb == rtcb) - { - sp = (FAR void *)up_getsp(); - if (up_interrupt_context()) - { -#if CONFIG_ARCH_INTERRUPTSTACK > 7 - ret = backtrace_branch( -# ifdef CONFIG_SMP - (uint32_t)arm_intstack_alloc() -# else - (uint32_t)&g_intstackalloc -# endif - + (CONFIG_ARCH_INTERRUPTSTACK & ~7), sp, - buffer, size); - if (ret < size) - { - sp = (FAR void *)CURRENT_REGS[REG_SP]; - ret += backtrace_branch(rtcb->stack_base_ptr + - rtcb->adj_stack_size, sp, - &buffer[ret], size - ret); - } -#else - sp = (FAR void *)CURRENT_REGS[REG_SP]; - ret = backtrace_branch(rtcb->stack_base_ptr + - rtcb->adj_stack_size, sp, - buffer, size); -#endif - } - else - { - ret = backtrace_branch(rtcb->stack_base_ptr + - rtcb->adj_stack_size, sp, - buffer, size); - } - } - else - { - flags = enter_critical_section(); - - ret = backtrace_branch(tcb->stack_base_ptr + - tcb->adj_stack_size, - (FAR void *)tcb->xcp.regs[REG_SP], - buffer, size); - - leave_critical_section(flags); - } - - return ret; -} diff --git a/arch/arm/src/armv7-r/arm_backtrace.c b/arch/arm/src/armv7-r/arm_backtrace.c deleted file mode 100644 index bb54d216ff..0000000000 --- a/arch/arm/src/armv7-r/arm_backtrace.c +++ /dev/null @@ -1,162 +0,0 @@ -/**************************************************************************** - * arch/arm/src/armv7-r/arm_backtrace.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 -#include -#include - -#include "sched/sched.h" - -#include "arm_internal.h" - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: backtrace - * - * Description: - * backtrace() parsing the return address through frame pointer - * - ****************************************************************************/ - -static int backtrace(FAR uintptr_t *base, FAR uintptr_t *limit, - FAR uintptr_t *fp, FAR uintptr_t *pc, - FAR void **buffer, int size) -{ - int i = 0; - - if (pc) - { - buffer[i++] = pc; - } - - for (; i < size; fp = (FAR uintptr_t *)*(fp - 1), i++) - { - if (fp > limit || fp < base || *fp == 0) - { - break; - } - - buffer[i] = (FAR void *)*fp; - } - - return i; -} - -/**************************************************************************** - * 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 - * - * Returned Value: - * up_backtrace() returns the number of addresses returned in buffer - * - ****************************************************************************/ - -int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size) -{ - FAR struct tcb_s *rtcb = running_task(); -#if CONFIG_ARCH_INTERRUPTSTACK > 7 - FAR void *istacklimit; -#endif - irqstate_t flags; - int ret; - - if (size <= 0 || !buffer) - { - return 0; - } - - if (tcb == NULL || tcb == rtcb) - { - if (up_interrupt_context()) - { -#if CONFIG_ARCH_INTERRUPTSTACK > 7 -# ifdef CONFIG_SMP - istacklimit = arm_intstack_top(); -# else - istacklimit = &g_intstacktop; -# endif /* CONFIG_SMP */ - ret = backtrace(istacklimit - (CONFIG_ARCH_INTERRUPTSTACK & ~7), - istacklimit, - (FAR void *)__builtin_frame_address(0), - NULL, buffer, size); -#else - ret = backtrace(rtcb->stack_base_ptr, - rtcb->stack_base_ptr + rtcb->adj_stack_size, - (FAR void *)__builtin_frame_address(0), - NULL, buffer, size); -#endif /* CONFIG_ARCH_INTERRUPTSTACK > 7 */ - if (ret < size) - { - ret += backtrace(rtcb->stack_base_ptr, - rtcb->stack_base_ptr + rtcb->adj_stack_size, - (FAR void *)CURRENT_REGS[REG_FP], - (FAR void *)CURRENT_REGS[REG_PC], - &buffer[ret], size - ret); - } - } - else - { - ret = backtrace(rtcb->stack_base_ptr, - rtcb->stack_base_ptr + rtcb->adj_stack_size, - (FAR void *)__builtin_frame_address(0), - NULL, buffer, size); - } - } - else - { - flags = enter_critical_section(); - - ret = backtrace(tcb->stack_base_ptr, - tcb->stack_base_ptr + tcb->adj_stack_size, - (FAR void *)tcb->xcp.regs[REG_FP], - (FAR void *)tcb->xcp.regs[REG_PC], - buffer, size); - - leave_critical_section(flags); - } - - return ret; -} diff --git a/arch/arm/src/arm/arm_backtrace.c b/arch/arm/src/common/arm_backtrace_fp.c similarity index 94% rename from arch/arm/src/arm/arm_backtrace.c rename to arch/arm/src/common/arm_backtrace_fp.c index 28165b55c2..8d4d4f7cdb 100644 --- a/arch/arm/src/arm/arm_backtrace.c +++ b/arch/arm/src/common/arm_backtrace_fp.c @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/arm/arm_backtrace.c + * arch/arm/src/common/arm_backtrace_fp.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -23,17 +23,19 @@ ****************************************************************************/ #include + #include -#include #include "sched/sched.h" #include "arm_internal.h" /**************************************************************************** - * Private Functions + * Pre-processor Definitions ****************************************************************************/ +#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_THUMB) + /**************************************************************************** * Name: backtrace * @@ -42,6 +44,9 @@ * ****************************************************************************/ +#ifdef CONFIG_MM_KASAN +__attribute__((no_sanitize_address)) +#endif static int backtrace(FAR uintptr_t *base, FAR uintptr_t *limit, FAR uintptr_t *fp, FAR uintptr_t *pc, FAR void **buffer, int size) @@ -94,6 +99,9 @@ static int backtrace(FAR uintptr_t *base, FAR uintptr_t *limit, * ****************************************************************************/ +#ifdef CONFIG_MM_KASAN +__attribute__((no_sanitize_address)) +#endif int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size) { FAR struct tcb_s *rtcb = running_task(); @@ -160,3 +168,4 @@ int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size) return ret; } +#endif /* CONFIG_FRAME_POINTER && !CONFIG_ARM_THUMB */ diff --git a/arch/arm/src/armv8-m/arm_backtrace.c b/arch/arm/src/common/arm_backtrace_thumb.c similarity index 50% rename from arch/arm/src/armv8-m/arm_backtrace.c rename to arch/arm/src/common/arm_backtrace_thumb.c index 2edefa65f1..ea766b0e5c 100644 --- a/arch/arm/src/armv8-m/arm_backtrace.c +++ b/arch/arm/src/common/arm_backtrace_thumb.c @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/armv8-m/arm_backtrace.c + * arch/arm/src/common/arm_backtrace_thumb.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -34,6 +34,8 @@ * Pre-processor Definitions ****************************************************************************/ +#ifdef CONFIG_ARM_THUMB + /* Macro and definitions for simple decoding of instuctions. * To check an instruction, it is ANDed with the IMASK_ and * the result is compared with the IOP_. The macro INSTR_IS @@ -42,12 +44,38 @@ #define INSTR_IS(i, o) (((i) & (IMASK_##o)) == (IOP_##o)) +#define IMASK_T_STMDB 0xfffff000 /* stmdb sp!,{..lr} */ +#define IOP_T_STMDB 0xe92d4000 + +#define IMASK_T_PUSH_LO 0xff00 /* push {reglist} (not LR) */ +#define IOP_T_PUSH_LO 0xb400 + +#define IMASK_T_PUSH 0xff00 /* push {reglist} (inc LR) */ +#define IOP_T_PUSH 0xb500 + +#define IMASK_T_VPUSH_16 0xffbf8f00 /* vpush d */ +#define IOP_T_VPUSH_16 0xed2d8b00 + +#define IMASK_T_VPUSH_8 0xffbf8f00 /* vpush s */ +#define IOP_T_VPUSH_8 0xed2d8a00 + +#define IMASK_T_SUB_SP_16 0xff80 /* sub sp, # */ +#define IOP_T_SUB_SP_16 0xb080 + +#define IMASK_T_SUB_SP_32 0xf2ff8f00 /* subw sp, sp, # */ +#define IOP_T_SUB_SP_32 0xf2ad0d00 + +#define IMASK_T_SUB_W_SP_32 0xfbff8f00 /* sub.w sp, sp, # */ +#define IOP_T_SUB_W_SP_32 0xf1ad0d00 + #define IMASK_T_BLX 0xff80 /* blx */ #define IOP_T_BLX 0x4780 #define IMASK_T_BL 0xf800 /* blx */ #define IOP_T_BL 0xf000 +#define INSTR_LIMIT 0x2000 + /**************************************************************************** * Private Data ****************************************************************************/ @@ -58,6 +86,35 @@ static FAR void **g_backtrace_code_regions; * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: getlroffset + * + * Description: + * getlroffset() returns the currect link address offset. + * + * Input Parameters: + * lr - Link register address + * + * Returned Value: + * Link address offset, 0 is returned if the lr is invalid. + * + ****************************************************************************/ + +#ifdef CONFIG_MM_KASAN +__attribute__((no_sanitize_address)) +#endif +static int getlroffset(FAR uint8_t *lr) +{ + lr = (FAR uint8_t *)((uintptr_t)lr & 0xfffffffe); + + if (((uintptr_t)lr & 0xffffffe0) == 0xffffffe0) + { + return 0; + } + + return (*(FAR uint16_t *)(lr - 4) & 0xf000) == 0xf000 ? 5 : 3; +} + /**************************************************************************** * Name: in_code_region * @@ -106,6 +163,190 @@ static bool in_code_region(FAR void *pc) return false; } +/**************************************************************************** + * Name: backtrace_push_internal + * + * Description: + * backtrace_push_internal() returns the currect link address from + * program counter and stack pointer + * + * Input Parameters: + * psp - Double poninter to the SP, this parameter will be changed if + * the corresponding LR address is successfully found. + * ppc - Double poninter to the PC, this parameter will be changed if + * the corresponding LR address is successfully found. + * + * Returned Value: + * Link address should be returned if successful + * Otherwise, NULL is returned + * + ****************************************************************************/ + +#ifdef CONFIG_MM_KASAN +__attribute__((no_sanitize_address)) +#endif +static FAR void *backtrace_push_internal(FAR void **psp, + FAR void **ppc) +{ + FAR uint8_t *sp = *psp; + FAR uint8_t *pc = *ppc; + FAR uint8_t *base; + FAR uint8_t *lr; + uint32_t ins32; + uint16_t ins16; + int offset = 1; + int frame; + int i; + + for (i = 0; i < INSTR_LIMIT; i += 2) + { + ins16 = *(FAR uint16_t *)(pc - i); + if (INSTR_IS(ins16, T_PUSH)) + { + frame = __builtin_popcount(ins16 & 0xff) + 1; + ins16 = *(FAR uint16_t *)(pc - i - 2); + if (INSTR_IS(ins16, T_PUSH_LO)) + { + offset += __builtin_popcount(ins16 & 0xff); + frame += offset - 1; + } + + break; + } + + ins32 = ins16 << 16; + ins32 |= *(FAR uint16_t *)(pc - i + 2); + if (INSTR_IS(ins32, T_STMDB)) + { + frame = __builtin_popcount(ins32 & 0xfff) + 1; + ins16 = *(FAR uint16_t *)(pc - i - 2); + if (INSTR_IS(ins16, T_PUSH_LO)) + { + offset += __builtin_popcount(ins16 & 0xff); + frame += offset - 1; + } + + break; + } + } + + if (i >= INSTR_LIMIT) + { + return NULL; + } + + base = pc - i; + + for (i = 0; i < INSTR_LIMIT && base + i < pc; ) + { + ins16 = *(FAR uint16_t *)(base + i); + if (INSTR_IS(ins16, T_SUB_SP_16)) + { + frame += (ins16 & 0x7f); + break; + } + + ins32 = ins16 << 16; + ins32 |= *(FAR uint16_t *)(base + i + 2); + if (INSTR_IS(ins32, T_SUB_SP_32)) + { + uint32_t shift = ins32 >> 24 & 0x4; + uint32_t sub = 0; + + if (shift) + { + sub = 1 << (shift - 1 + 8); + } + + frame += (sub + (ins32 & 0xff) + + ((ins32 & 0x7000) >> 4)) / sizeof(uint32_t); + break; + } + else if (INSTR_IS(ins32, T_SUB_W_SP_32)) + { + uint32_t shift; + uint32_t sub; + + sub = (ins32 & 0x7f) + 0x80; + shift = (ins32 >> 7) & 0x1; + shift += ((ins32 >> 12) & 0x7) << 1; + shift += ((ins32 >> 26) & 0x1) << 4; + + frame += sub << (30 - shift); + break; + } + else if (INSTR_IS(ins32, T_VPUSH_16)) + { + frame += (ins32 & 0xff); + } + else if (INSTR_IS(ins32, T_VPUSH_8)) + { + frame += (ins32 & 0xff) / 2; + } + + i += ((ins16 & 0xf800) >= 0xe800) ? 4 : 2; + } + + lr = (FAR uint8_t *)*((FAR uint32_t *)sp + frame - offset); + if (!in_code_region(lr)) + { + return NULL; + } + + offset = getlroffset(lr); + if (offset == 0) + { + return NULL; + } + + *psp = (FAR uint32_t *)sp + frame; + *ppc = lr - offset; + + return *ppc; +} + +/**************************************************************************** + * Name: backtrace_push + * + * Description: + * backtrace_push() parsing the return address through instruction + * + ****************************************************************************/ + +#ifdef CONFIG_MM_KASAN +__attribute__((no_sanitize_address)) +#endif +static int backtrace_push(FAR void *limit, FAR void **sp, + FAR void *pc, FAR void **buffer, int size) +{ + int i = 0; + + if (!in_code_region(pc)) + { + return 0; + } + + pc = (uintptr_t)pc & 0xfffffffe; + + buffer[i++] = pc; + + for (; i < size; i++) + { + if (*sp >= limit) + { + break; + } + + buffer[i] = backtrace_push_internal(sp, &pc); + if (!buffer[i]) + { + break; + } + } + + return i; +} + /**************************************************************************** * Name: backtrace_branch * @@ -165,10 +406,10 @@ static int backtrace_branch(FAR void *limit, FAR void *sp, ****************************************************************************/ /**************************************************************************** - * Name: arm_backtrace_init_code_regions + * Name: up_backtrace_init_code_regions * * Description: - * The up call arm_backtrace_init_code_regions() will set the start + * The up call up_backtrace_init_code_regions() will set the start * and end addresses of the customized program sections, this method * will help the different boards to configure the current text * sections for some complicate platfroms @@ -188,14 +429,14 @@ static int backtrace_branch(FAR void *limit, FAR void *sp, * NULL, NULL, * }; * - * arm_backtrace_init_code_regions(g_code_regions); + * up_backtrace_init_code_regions(g_code_regions); * ****************************************************************************/ #ifdef CONFIG_MM_KASAN __attribute__((no_sanitize_address)) #endif -void arm_backtrace_init_code_regions(FAR void **regions) +void up_backtrace_init_code_regions(FAR void **regions) { g_backtrace_code_regions = regions; } @@ -247,49 +488,75 @@ int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size) if (tcb == rtcb) { sp = (FAR void *)up_getsp(); + if (up_interrupt_context()) { #if CONFIG_ARCH_INTERRUPTSTACK > 7 - ret = backtrace_branch( + ret = backtrace_push( # ifdef CONFIG_SMP - (uint32_t)arm_intstack_alloc() + arm_intstack_top(), # else - (uint32_t)&g_intstackalloc -# endif - + (CONFIG_ARCH_INTERRUPTSTACK & ~7), sp, - buffer, size); + &g_intstacktop, +# endif /* CONFIG_SMP */ + &sp, (FAR void *)up_backtrace + 10, + buffer, size); +#else + ret = backtrace_push(rtcb->stack_base_ptr + + rtcb->adj_stack_size, + &sp, (FAR void *)up_backtrace + 10, + buffer, size); +#endif if (ret < size) { sp = (FAR void *)CURRENT_REGS[REG_SP]; - ret += backtrace_branch(rtcb->stack_base_ptr + - rtcb->adj_stack_size, sp, - &buffer[ret], size - ret); + ret += backtrace_push(rtcb->stack_base_ptr + + rtcb->adj_stack_size, &sp, + (FAR void *)CURRENT_REGS[REG_PC], + &buffer[ret], size - ret); } -#else - sp = (FAR void *)CURRENT_REGS[REG_SP]; - ret = backtrace_branch(rtcb->stack_base_ptr + - rtcb->adj_stack_size, sp, - buffer, size); -#endif } else { - ret = backtrace_branch(rtcb->stack_base_ptr + - rtcb->adj_stack_size, sp, - buffer, size); + ret = backtrace_push(rtcb->stack_base_ptr + + rtcb->adj_stack_size, &sp, + (FAR void *)up_backtrace + 10, + buffer, size); + } + + if (ret < size) + { + ret += backtrace_branch(rtcb->stack_base_ptr + + rtcb->adj_stack_size, sp, + &buffer[ret], size - ret); } } else { + ret = 0; + flags = enter_critical_section(); - ret = backtrace_branch(tcb->stack_base_ptr + - tcb->adj_stack_size, - (FAR void *)tcb->xcp.regs[REG_SP], - buffer, size); + buffer[ret++] = tcb->xcp.regs[REG_PC]; + + if (ret < size) + { + sp = (FAR void *)tcb->xcp.regs[REG_SP]; + ret += backtrace_push(tcb->stack_base_ptr + + tcb->adj_stack_size, &sp, + (FAR void *)tcb->xcp.regs[REG_LR], + &buffer[ret], size - ret); + + if (ret < size) + { + ret += backtrace_branch(tcb->stack_base_ptr + + tcb->adj_stack_size, sp, + &buffer[ret], size - ret); + } + } leave_critical_section(flags); } return ret; } +#endif /* CONFIG_ARM_THUMB */