Valgrind如何在编译的C程序中访问内存分配的行号,我如何才能做到同样的事情?

Valgrind如何在编译的C程序中访问内存分配的行号,我如何才能做到同样的事情?,c,compilation,valgrind,diagnostics,C,Compilation,Valgrind,Diagnostics,当我运行一个简单的Valgrind命令时,例如 valgrind --leak-check=yes ./my_program …Valgrind产生的错误输出显示了在源代码中内存分配的位置以及释放的位置。Valgrind是如何做到这一点的?我怎么能自己用程序的代码来做呢?如果有帮助,在我的GCC makefile中为编译定义的CFLAGS参数是: CFLAGS=-c -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -g -Og

当我运行一个简单的Valgrind命令时,例如

valgrind --leak-check=yes ./my_program
…Valgrind产生的错误输出显示了在源代码中内存分配的位置以及释放的位置。Valgrind是如何做到这一点的?我怎么能自己用程序的代码来做呢?如果有帮助,在我的GCC makefile中为编译定义的CFLAGS参数是:

CFLAGS=-c -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -g -Og -std=c11 -pedantic
…在编译的C程序中,访问行数的内存分配,我如何才能做到同样的

预定义的宏,如和,可在C源代码中用于输出有关发生事件的位置的信息。宏的数量和种类在某种程度上取决于环境__例如,函数是一个扩展,不在标准指定的预定义宏中,如注释中所述。(有关用法的其他提示,请参见上面的链接。)

在本例中,这些宏用于显示事件发生在哪个文件、函数和哪一行:

char buf[100];
sprintf(buf, "%p (%s() %s() line# %d)\n", malloc(10), __FILE__, __FUNCTION__, __LINE__);
printf(buf);//(Or more likely usage, write to a log file)
注意,此示例没有错误检查/处理,例如检查
malloc()
的返回值,这总是一个好主意

Valgrind产生的错误输出显示了在源代码中的何处进行了内存分配,以及在何处释放了内存。Valgrind是如何做到这一点的

使用valgrind时,不会直接启动程序。相反,valgrind是在一个允许它首先进行监控的环境和手段中进行这项工作的。这包括但不限于用其自身的分配函数替换标准库的正常实现。正是这些可选的分配函数使Valgrind能够跟踪二进制文件中发生分配和释放的位置

使用
-g
选项编译时,将源行号与已编译二进制文件中的特定指令关联所需的信息是二进制文件中包含的调试信息的一部分。如果省略
-g
,您会发现Valgrind的输出对错误位置的信息较少

我怎么能自己用程序的代码来做呢

您还可以提供自己的
malloc
等和
免费
功能。您可以使它们在整个程序中使用,而不是在标准库的版本中使用,尽管细节可能部分取决于您的C实现。正确地做到这一点非常重要,细节取决于系统

这些函数可以识别调用它们的点的方法甚至更为重要,并且依赖于系统。C语言没有定义任何类型的内省特性,比如这需要什么,所以您需要自己提供

标准C也没有定义程序可以从自己的二进制文件访问调试信息的任何方式,甚至没有定义找到自己的二进制文件的任何可靠方式,也没有定义“调试信息”。Valgrind在这方面比程序本身有一个明显的优势:因为Valgrind启动了程序,Valgrind能够知道它正在启动什么二进制文件


总的来说,答案是,如果你必须首先问这个问题,那么你可能根本没有能力去做你所要求的。相反,您应该寻找一个现有的工具,该工具与您想要的足够接近(可能是valgrind本身),或者更改您的需求。特别是,您应该考虑在@ Ryyk的回答中描述的基于预处理器的机制是否提供了一种接近您所想的方法。

一个提示:“代码> -g/c>用于在二进制中添加调试信息,可以用于显示这些信息。您可以查看LIBFD,例如添加,像valgrind这样的框架向现有的库函数添加了钩子,并使用这些宏和更多宏插入这些信息,然后在调试期间使用它们。我对valgrind不太自信(从未看过源代码),但这通常是一种策略。我这样做是为了我的一个项目。如果您确实知道valgrinds会这样做,请随意添加,否则,请在评论中作为提示。