GDB 调试器 - 未定义“malloc”。尝试使用调试器分配 C 数组

Posted

技术标签:

【中文标题】GDB 调试器 - 未定义“malloc”。尝试使用调试器分配 C 数组【英文标题】:GDB Debugger - "malloc" not defined. Trying to assign C array with debugger 【发布时间】:2022-01-18 06:06:15 【问题描述】:

我使用here 的 gcc-arm-none-eabi 工具链(一种为 gdb 提供支持 python3 的自定义工具链)编译了一些软件以在嵌入式 NRF24 目标上运行。我基本上在尝试,malloc 在运行时来自 GDB 调试器控制台的一个数组,然后用我提供的元素填充它。

我在 .c 文件中定义了一个指针,例如:static float32_t *array;。 然后我想从 GDB 控制台内部调用一个类似 cmd 的命令:call (void*) malloc(num_of_elements*sizeof(float32_t)) 在运行时分配一个数组,然后用可能的元素填充它:call (void*) memcpy(array, var1, var2... var n, n)

我的问题是 GDB 调试器找不到 malloc stdlib 函数。如果我这样做:

break malloc 
Function "malloc" not defined.
Make breakpoint pending on future shared library load? (y or [n]) [answered N; input not from terminal]

它找不到这个函数,尽管找到 fns 很好,例如memcpy,但我不太明白为什么会这样。

我感觉这可能与链接有关,程序是用 Makefile 构建的,最后的标志可能很有趣:

LIB_FILES += \
  $(SDK_ROOT)/components/toolchain/cmsis/dsp/GCC/libarm_cortexM4lf_math.a \

# Optimization flags
OPT = -O0 -g3
# Uncomment the line below to enable link time optimization
#OPT += -flto

# C flags common to all targets
CFLAGS += $(OPT)
CFLAGS += -DBOARD_PCA10056
CFLAGS += -DARM_MATH_CM4
CFLAGS += -DBSP_DEFINES_ONLY
CFLAGS += -DCONFIG_GPIO_AS_PINRESET
CFLAGS += -DFLOAT_ABI_HARD
CFLAGS += -DNRF52840_XXAA
CFLAGS += -mcpu=cortex-m4
CFLAGS += -mthumb -mabi=aapcs
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
# keep every function in a separate section, this allows linker to discard unused ones
CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing
CFLAGS += -fno-builtin -fshort-enums

CFLAGS += -DDEV8_PINOUT
CFLAGS += -DNUM_FLASH_BLOCKS=128
CFLAGS += -DDEBUG
CFLAGS += -DNRF_LOG_ENABLED=1
CFLAGS += -DNRF_LOG_BACKEND_UART_ENABLED=1

# C++ flags common to all targets
CXXFLAGS += $(OPT)
# Assembler flags common to all targets
ASMFLAGS += $(OPT)
ASMFLAGS += -mcpu=cortex-m4
ASMFLAGS += -mthumb -mabi=aapcs
ASMFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
ASMFLAGS += -DBOARD_PCA10056
ASMFLAGS += -DBSP_DEFINES_ONLY
ASMFLAGS += -DCONFIG_GPIO_AS_PINRESET
ASMFLAGS += -DFLOAT_ABI_HARD
ASMFLAGS += -DNRF52840_XXAA
ASMFLAGS += -DARM_MATH_CM4

# Linker flags
LDFLAGS += $(OPT)
LDFLAGS += -mthumb -mabi=aapcs -L$(SDK_ROOT)/modules/nrfx/mdk -T$(LINKER_SCRIPT)
LDFLAGS += -mcpu=cortex-m4
LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
# let linker dump unused sections
LDFLAGS += -Wl,--gc-sections
# use newlib in nano version
LDFLAGS += --specs=nano.specs
LDFLAGS += -Wl,--print-memory-usage

nrf52840_xxaa: CFLAGS += -D__HEAP_SIZE=8192
nrf52840_xxaa: CFLAGS += -D__STACK_SIZE=8192
nrf52840_xxaa: ASMFLAGS += -D__HEAP_SIZE=8192
nrf52840_xxaa: ASMFLAGS += -D__STACK_SIZE=8192

# Add standard libraries at the very end of the linker input, after all objects
# that may need symbols provided by these libraries.
LIB_FILES += -lc -lnosys -lm

为了调试,我将 GDB 与 Jlink 服务器类型设置一起使用。

【问题讨论】:

【参考方案1】:

您的代码需要显式引用该符号以强制它链接,并且您需要防止链接优化删除未使用的引用。与其进行具有潜在不良副作用的虚拟调用,不如通过函数指针实例化简单地引用该符号:

 void* (*volatile force_malloc_link)(size_t) = &malloc ;

或者更简单,因为您实际上不会通过指针调用函数:

volatile void* force_link_malloc = &malloc ;

您可以使用宏来为您希望链接的任何符号使其通用:

#define FORCE_LINK( sym ) volatile void* force_link_ ## sym = &sym 

您还可以强制链接整个库(如果有空间)-How to force gcc to link an unused static library。那里的答案之一解释了如何解压缩静态库并链接各个目标文件。

【讨论】:

请注意,如果force_link_malloc 没有实际使用,GCC 可能会很好地对其进行优化,所以这个解决方案并不好。 @EmployedRussian - 这就是volatile 的用途。此外,在任何情况下,您都很少会在 GDB 中运行优化代码。不是更好 - 我从来没有提出过这样的要求 - 只是一个替代方案。 volatile 不保证您声称它的作用。使用 GDB 调试优化代码在我的家乡很常见。 @EmployedRussian :它不必保证它 - 如果它做到了,它就会做到。如果从经验上看它是有效的,那么标准所说的可能会发生什么并不重要——因为它没有发生。要求是使 malloc 在 GDB 中可用 - 如果 malloc 在 GDB 在此实例中 中可用;完成工作 - 没有副作用。我建议,出现不良副作用的可能性是一个更严重的问题。当声明具有全局范围时,编译器无法将其优化掉(尽管可以想象链接器可以)。【参考方案2】:

找不到这个函数

该函数可能未链接到您的二进制文件中。

您的二进制文件是否调用 malloc 其他地方? 您是否链接到libc.solibc.anm a.out | grep ' malloc' 找到了吗?

找到 fns 就好了,比如memcpy

如果您的二进制调用memcpy 并且您链接到libc.a,那么memcpy 实现将被链接。使用上面相同的nm 命令将显示memcpy 符号存在并且@987654331 @ 不是。

如果您想在运行时调用malloc,您需要确保它已链接。实现此目的的一种方法是添加:

const char *argv0;
int main(int argc, char *argv[])

  argv0 = strdup(argv[0]);  // This should guarantee that malloc is linked in.
  // rest of the program

【讨论】:

啊,是的,添加您的代码 sn-p 似乎可以完成这项工作,谢谢。其实这也让我意识到自己的菜鸟错误。 Malloc 在我的代码中被调用,但在一个实际上无法通过正常程序流程访问的函数中。聪明的编译器当然决定不链接它。哎呀! 调用strdup() 强制malloc() 链接而不是直接调用malloc() 是否有特定原因?我建议free( malloc( 0 ) ) ; 可能会产生更少的副作用并且没有内存泄漏。 @Clifford 没有特别的原因。你可以只使用argv0 = malloc(1); 使用free(malloc(0)) 不起作用——GCC 知道mallocfree 做了什么并且可以优化它。 公平点重新 malloc(0)。

以上是关于GDB 调试器 - 未定义“malloc”。尝试使用调试器分配 C 数组的主要内容,如果未能解决你的问题,请参考以下文章

如何使 GDB 与外部程序一起工作

调试 gdb tui 定义新布局

GDB - 未找到调试符号 -

使gdb在成功终止时自动退出?

GDB 和 OpenOCD - 调试结束后重置或恢复

Linux学习: 使用gdb和gdbserver进行调试