diff --git a/include/execinfo.h b/include/execinfo.h new file mode 100644 index 0000000000..bd47b7a347 --- /dev/null +++ b/include/execinfo.h @@ -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 */ diff --git a/libs/libc/Kconfig b/libs/libc/Kconfig index 0496f030df..994b9174ed 100644 --- a/libs/libc/Kconfig +++ b/libs/libc/Kconfig @@ -29,3 +29,4 @@ source libs/libc/wqueue/Kconfig source libs/libc/hex2bin/Kconfig source libs/libc/userfs/Kconfig source libs/libc/builtin/Kconfig +source libs/libc/debug/Kconfig diff --git a/libs/libc/Makefile b/libs/libc/Makefile index 4f1657fc64..8d3be3dbe7 100644 --- a/libs/libc/Makefile +++ b/libs/libc/Makefile @@ -25,6 +25,7 @@ include assert/Make.defs include audio/Make.defs include builtin/Make.defs include ctype/Make.defs +include debug/Make.defs include dirent/Make.defs include dlfcn/Make.defs include endian/Make.defs diff --git a/libs/libc/debug/Kconfig b/libs/libc/debug/Kconfig new file mode 100644 index 0000000000..fd13b04587 --- /dev/null +++ b/libs/libc/debug/Kconfig @@ -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 diff --git a/libs/libc/debug/Make.defs b/libs/libc/debug/Make.defs new file mode 100644 index 0000000000..5d42e13d86 --- /dev/null +++ b/libs/libc/debug/Make.defs @@ -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 diff --git a/libs/libc/debug/lib_backtrace.c b/libs/libc/debug/lib_backtrace.c new file mode 100644 index 0000000000..95a7c6bca3 --- /dev/null +++ b/libs/libc/debug/lib_backtrace.c @@ -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 + +#include +#include +#include + +/**************************************************************************** + * 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; +}