Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

arch/x86_64:Add FP backtrace function #13551

Merged
merged 1 commit into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ config ARCH_X86_64
select PCI_LATE_DRIVERS_REGISTER if PCI
select LIBC_ARCH_ELF_64BIT if LIBC_ARCH_ELF
select ARCH_TOOLCHAIN_GNU
select ARCH_HAVE_BACKTRACE
---help---
x86-64 architectures.

Expand Down
18 changes: 18 additions & 0 deletions arch/x86_64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,24 @@ config ARCH_CHIP_X86_64_CUSTOM

endchoice

if SCHED_BACKTRACE
choice
prompt "Choose x86_64 unwinder"
default X86_64_UNWINDER_FRAME_POINTER
---help---
This determines which method will be used for unwinding nuttx stack
traces for debug.

config X86_64_UNWINDER_FRAME_POINTER
bool "Frame pointer unwinder"
select FRAME_POINTER
---help---
This option enables the frame pointer unwinder for unwinding
nuttx stack traces.

endchoice # Choose x86_64 unwinder
endif

# CPU features

config ARCH_HAVE_MMX
Expand Down
4 changes: 4 additions & 0 deletions arch/x86_64/src/common/Toolchain.defs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ else ifeq ($(CONFIG_DEBUG_FULLOPT),y)
ARCHOPTIMIZATION += -Os
endif

ifeq ($(CONFIG_FRAME_POINTER),y)
ARCHOPTIMIZATION += -fno-omit-frame-pointer -fno-optimize-sibling-calls
endif

ARCHCPUFLAGS = -fPIC -fno-stack-protector -mno-red-zone -mrdrnd
ARCHPICFLAGS = -fPIC
ARCHWARNINGS = -Wall -Wstrict-prototypes -Wshadow -Wundef
Expand Down
4 changes: 4 additions & 0 deletions arch/x86_64/src/intel64/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ set(SRCS
intel64_check_capability.c
intel64_cpu.c)

if(CONFIG_x86_64_UNWINDER_FRAME_POINTER)
list(APPEND SRCS intel64_backtrace_fp.c)
endif()

if(CONFIG_MM_PGALLOC)
list(APPEND SRCS intel64_pgalloc.c)
endif()
Expand Down
4 changes: 4 additions & 0 deletions arch/x86_64/src/intel64/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ CHIP_CSRCS = intel64_start.c intel64_handlers.c intel64_idle.c intel64_lowsetup
CHIP_CSRCS += intel64_serial.c intel64_rng.c intel64_check_capability.c
CHIP_CSRCS += intel64_cpu.c

ifeq ($(CONFIG_x86_64_UNWINDER_FRAME_POINTER),y)
CMN_CSRCS += intel64_backtrace_fp.c
endif

ifeq ($(CONFIG_MM_PGALLOC),y)
CHIP_CSRCS += intel64_pgalloc.c
endif
Expand Down
169 changes: 169 additions & 0 deletions arch/x86_64/src/intel64/intel64_backtrace_fp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/****************************************************************************
* arch/x86_64/src/intel64/intel64_backtrace_fp.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 "sched/sched.h"

#include <x86_64_internal.h>

/****************************************************************************
* Pre-processor Definitions
****************************************************************************/

/****************************************************************************
* Name: backtrace
*
* Description:
* backtrace() parsing the return address through frame pointer
*
****************************************************************************/

nosanitize_address
static int backtrace(uintptr_t *base, uintptr_t *limit,
uintptr_t *rbp, uintptr_t *rip,
void **buffer, int size, int *skip)
{
int i = 0;

if (rip)
{
if ((*skip)-- <= 0)
{
buffer[i++] = rip;
}
}

for (; i < size; rbp = (uintptr_t *)(*rbp))
{
if (rbp > limit || rbp < base ||
*(uintptr_t *)rbp == 0)
{
break;
}

if ((*skip)-- <= 0)
{
buffer[i++] = (uintptr_t *)(*(rbp + 1));
}
}

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
* skip - number of addresses to be skipped
*
* Returned Value:
* up_backtrace() returns the number of addresses returned in buffer
*
* Assumptions:
* Have to make sure tcb keep safe during function executing, it means
* 1. Tcb have to be self or not-running. In SMP case, the running task
* PC & SP cannot be backtrace, as whose get from tcb is not the newest.
* 2. Tcb have to keep not be freed. In task exiting case, have to
* make sure the tcb get from pid and up_backtrace in one critical
* section procedure.
*
****************************************************************************/

int up_backtrace(struct tcb_s *tcb,
void **buffer, int size, int skip)
{
struct tcb_s *rtcb = running_task();
int ret;

if (size <= 0 || !buffer)
{
return 0;
}

if (tcb == NULL || tcb == rtcb)
{
if (up_interrupt_context())
{
#if CONFIG_ARCH_INTERRUPTSTACK > 3
void *istackbase = (void *)up_get_intstackbase(this_cpu());

ret = backtrace(istackbase,
istackbase + IRQ_STACK_SIZE,
(void *)__builtin_frame_address(0),
NULL, buffer, size, &skip);
#else
ret = backtrace(rtcb->stack_base_ptr,
rtcb->stack_base_ptr + rtcb->adj_stack_size,
(void *)__builtin_frame_address(0),
NULL, buffer, size, &skip);
#endif /* CONFIG_ARCH_INTERRUPTSTACK > 3 */
if (ret < size)
{
ret += backtrace(rtcb->stack_base_ptr,
rtcb->stack_base_ptr + rtcb->adj_stack_size,
(void *)up_current_regs()[REG_RBP],
(void *)up_current_regs()[REG_RIP],
&buffer[ret], size - ret, &skip);
}
}
else
{
ret = backtrace(rtcb->stack_base_ptr,
rtcb->stack_base_ptr + rtcb->adj_stack_size,
(void *)__builtin_frame_address(0),
NULL, buffer, size, &skip);
}
}
else
{
ret = backtrace(tcb->stack_base_ptr,
tcb->stack_base_ptr + tcb->adj_stack_size,
(void *)tcb->xcp.regs[REG_RBP],
(void *)tcb->xcp.regs[REG_RIP],
buffer, size, &skip);
}

return ret;
}
2 changes: 1 addition & 1 deletion arch/x86_64/src/intel64/intel64_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ uint64_t *isr_handler(uint64_t *regs, uint64_t irq)
"with error code %" PRId64 ":\n",
irq, regs[REG_ERRCODE]);

up_dump_register(regs);
PANIC_WITH_REGS("panic", regs);

up_trash_cpu();
break;
Expand Down
2 changes: 1 addition & 1 deletion arch/x86_64/src/intel64/intel64_initialstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ void up_initial_state(struct tcb_s *tcb)
*/

xcp->regs[REG_RSP] = (uint64_t)xcp->regs - 8;
xcp->regs[REG_RBP] = (uint64_t)xcp->regs - 8;
xcp->regs[REG_RBP] = 0;

/* Save the task entry point */

Expand Down
13 changes: 0 additions & 13 deletions arch/x86_64/src/intel64/intel64_regdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,18 +154,5 @@ void up_dump_register(void *dumpregs)
regs[REG_R14], regs[REG_R15]);
_alert("Dumping Stack (+-64 bytes):\n");

if (regs[REG_RSP] > 0 && regs[REG_RSP] < 0x1000000)
{
print_mem((void *)regs[REG_RSP] - 512,
128 * 0x200000 - regs[REG_RSP] + 512);
}
else
{
print_mem((void *)regs[REG_RSP] - 512, 1024);
}

#ifdef CONFIG_DEBUG_NOOPT
backtrace(regs[REG_RBP]);
#endif
_alert("-----------------------------------------\n");
}
Loading