由于工作需要,特此记录学习过程中遇到的问题和解决办法,亦作日后备忘。
声明
- 如无特别说明,本文(以及同系列文章)将在合适的上下文中以“文章”指代自身(以及同系列文章);
- 如无特别说明,文章将在合适的上下文中以“工具”指代“自定义Valgrind工具”;
- 如无特别说明,文章提到的文件名及路径均为相对Valgrind源码的文件名及路径;
- 文章将以
mytool
作为工具的名称,并以mt
作为工具的“两字母缩写”(Valgrind官方文档要求一个工具要有两字母缩写); - 文章将以
mytool
作为存放工具的目录; - 文章将不对其所使用的反身代词“我们”和“我”做区分,且使用“我们”和“我”时没有特殊的含义(我也不知道我是谁);
- 文章作者不会用
automake
和autoconf
等工具; - 为了保护相关者的隐私,文章中(意外地或非意外地)提到的任何人名均为假名;
- 文章的主要目的是作为备忘,以便在文章作者遭遇不可预料的意外时可以恢复其工作。所述“意外”包括但不限于相关资料的丢失、作者遗忘相关内容、作者身体停止工作;
- 对于非作者本人,文章仅供参考,文章作者将不会对任何集体、组织或个人由于阅读此文章而造成的任何形式的损失负责。
获取和编译Valgrind源码
此步骤较为简单,不在此赘述。
创建空白自定义工具
下面将展示如何创建一个空白的Valgrind工具,并给出例子。
注册工具函数
根据Valgrind官方文档,一个工具必须向Valgrind核心(core
)注册以下四个函数:
void pre_clo_init()
:在Valgrind处理clo(command line options)前,此函数将进行工具的初始化工作,必须在这里向Valgrind核心注册工具的若干“detail”(名称、版本、描述等)。在此初始化函数中,还可以使用VG_(track_*)()
宏注册若干事件监听器。可供注册的函数见include/pub_tool_tooliface.h
;void post_clo_init()
:在Valgrind处理clo(command line options)后,此函数将进行工具的初始化工作,用于根据命令行参数进行初始化工作。此函数在上述初始化函数中使用VG_(basic_tool_funcs)()
宏注册。如不需要读取命令行参数,则此函数可以放空;IRSB* instrument(VgCallbackClosure* closure, IRSB* bb, const VexGuestLayout* layout, const VexGuestExtents* vge, const VexArchInfo* archinfo_host, IRType gWordTy, IRType hWordTy)
:插桩函数,若直接返回未经处理的IRSB *bb
,则相当于使程序照常运行,不做对程序正文作任何操作。此函数在上述第一个初始化函数中使用VG_(basic_tool_funcs)()
宏注册。此函数接受的VEX IR(Valgrind’s RISC-like intermediate language)格式文档见VEX/pub/libvex_ir.h
;void fini(Int exitcode)
:官方文档未说明,疑似为完成收尾工作的函数,负责分析工作的总结以及日志文件或报告的生成(写出)。此函数在上述第一个初始化函数中使用VG_(basic_tool_funcs)()
宏注册。
一般地,上述四个函数名需要加上工具两字母缩写+下划线前缀,例如:mt_pre_clo_init
。
一个空白工具的例子
下面给出一个空白工具的源代码:
// File name: mytool/mt_main.c
#include "pub_tool_basics.h"
#include "pub_tool_tooliface.h"
static void mt_post_clo_init(void) {
}
static
IRSB* mt_instrument ( VgCallbackClosure* closure,
IRSB* bb,
const VexGuestLayout* layout,
const VexGuestExtents* vge,
const VexArchInfo* archinfo_host,
IRType gWordTy, IRType hWordTy ) {
return bb;
}
static void mt_fini(Int exitcode) {
}
static void mt_pre_clo_init(void) {
VG_(details_name) ("Mytool");
VG_(details_version) (NULL);
VG_(details_description) ("Valgrind playground");
VG_(details_copyright_author)(
"Copyright (C) 2019, by Untitled.");
VG_(details_bug_reports_to) (VG_BUGS_TO);
VG_(details_avg_translation_sizeB) ( 275 );
VG_(basic_tool_funcs) (mt_post_clo_init,
mt_instrument,
mt_fini);
/* No needs, no core events to track */
}
VG_DETERMINE_INTERFACE_VERSION(mt_pre_clo_init)
然后,我们需要将mytool/mt_main.c
加入到Android.mk
中,可以参考none
工具:
# Build mytool-$(TARGET_ARCH)-linux
vg_local_module := mytool
vg_local_module_class := SHARED_LIBRARIES
vg_local_target := EXECUTABLE
vg_local_no_crt := true
vg_local_without_system_shared_libraries := true
vg_local_src_files := \
mytool/mt_main.c
vg_local_ldflags := $(tool_ldflags)
vg_local_cflags := $(common_cflags)
vg_local_static_libraries := libcoregrind libvex
include $(LOCAL_PATH)/Android.build_all.mk
查看结果
编译后使用valgrind --tool=mytool date
测试,看到类似
==1472== Mytool, Valgrind playground
==1472== Copyright (C) 2019, by Untitled.
==1472== Using Valgrind-x.x.x and LibVEX; rerun with -h for copyright info
==1472== Command: date
==1472==
output ofdate
==1472==
的输出即说明工具成功添加并运行。