libc/execinfo: add backtrace support based on EABI Unwinder

1. Flags < -funwind-tables > is required
2. Keep the section ".exidx" in linker script

Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
chao.an 2021-03-30 17:48:42 +08:00 committed by David Sidrane
parent 58bd0468ab
commit 27dd771336
6 changed files with 216 additions and 0 deletions

34
include/execinfo.h Normal file
View File

@ -0,0 +1,34 @@
/****************************************************************************
* include/execinfo.h
*
* 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.
*
****************************************************************************/
#ifndef __INCLUDE_EXECINFO_H
#define __INCLUDE_EXECINFO_H
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/* Store up to SIZE return address of the current program state in
* ARRAY and return the exact number of values stored.
*/
extern int backtrace(FAR void **buffer, int size);
#endif /* __INCLUDE_EXECINFO_H */

View File

@ -29,3 +29,4 @@ source libs/libc/wqueue/Kconfig
source libs/libc/hex2bin/Kconfig source libs/libc/hex2bin/Kconfig
source libs/libc/userfs/Kconfig source libs/libc/userfs/Kconfig
source libs/libc/builtin/Kconfig source libs/libc/builtin/Kconfig
source libs/libc/debug/Kconfig

View File

@ -25,6 +25,7 @@ include assert/Make.defs
include audio/Make.defs include audio/Make.defs
include builtin/Make.defs include builtin/Make.defs
include ctype/Make.defs include ctype/Make.defs
include debug/Make.defs
include dirent/Make.defs include dirent/Make.defs
include dlfcn/Make.defs include dlfcn/Make.defs
include endian/Make.defs include endian/Make.defs

22
libs/libc/debug/Kconfig Normal file
View File

@ -0,0 +1,22 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
# These are library functions that may be overriden by architecture-
# specific implementations. Not all architectures support implementations
# for every library function.
menu "Library Debugging"
config EABI_UNWINDER
bool "EABI Stack Unwinder"
default "n"
---help---
This option enables stack unwinding support in NuttX
using the information automatically generated by the
compiler. The resulting image is slightly bigger but
the performance is not affected. Currently, this feature
only works with EABI compilers.
endmenu # Library Debugging Support

30
libs/libc/debug/Make.defs Normal file
View File

@ -0,0 +1,30 @@
############################################################################
# libs/libc/debug/Make.defs
#
# 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.
#
############################################################################
ifeq ($(CONFIG_EABI_UNWINDER),y)
CSRCS += lib_backtrace.c
endif
# Include debug build support
DEPPATH += --dep-path debug
VPATH += :debug

View File

@ -0,0 +1,128 @@
/****************************************************************************
* libs/libc/debug/lib_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 <nuttx/config.h>
#include <sys/types.h>
#include <execinfo.h>
#include <unwind.h>
/****************************************************************************
* Private Data Types
****************************************************************************/
struct trace_arg
{
FAR void **array;
_Unwind_Word cfa;
int cnt;
int size;
};
/****************************************************************************
* Private Functions
****************************************************************************/
static inline weak_function
FAR void *unwind_arch_adjustment(FAR void *prev, FAR void *addr)
{
return addr;
}
static _Unwind_Reason_Code
backtrace_helper(FAR struct _Unwind_Context *ctx, FAR void *a)
{
FAR struct trace_arg *arg = a;
/* We are first called with address in the backtrace function.
* Skip it.
*/
if (arg->cnt != -1)
{
arg->array[arg->cnt] = (FAR void *)_Unwind_GetIP(ctx);
if (arg->cnt > 0)
{
arg->array[arg->cnt]
= unwind_arch_adjustment(arg->array[arg->cnt - 1],
arg->array[arg->cnt]);
}
/* Check whether we make any progress. */
_Unwind_Word cfa = _Unwind_GetCFA(ctx);
if (arg->cnt > 0 &&
arg->array[arg->cnt - 1] == arg->array[arg->cnt] &&
cfa == arg->cfa)
{
return _URC_END_OF_STACK;
}
arg->cfa = cfa;
}
if (++arg->cnt == arg->size)
{
return _URC_END_OF_STACK;
}
return _URC_NO_REASON;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/* Store up to SIZE return address of the current program state in
* ARRAY and return the exact number of values stored.
*/
int backtrace(FAR void **buffer, int size)
{
struct trace_arg arg;
arg.array = buffer;
arg.cfa = 0;
arg.size = size;
arg.cnt = -1;
if (size <= 0)
{
return 0;
}
_Unwind_Backtrace(backtrace_helper, &arg);
/* _Unwind_Backtrace seems to put NULL address above
* _start. Fix it up here.
*/
if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
{
--arg.cnt;
}
return arg.cnt != -1 ? arg.cnt : 0;
}