由于工作需要,特此记录学习过程中遇到的问题和解决办法,亦作日后备忘。

声明

  • 如无特别说明,本文(以及同系列文章)将在合适的上下文中以“文章”指代自身(以及同系列文章);
  • 如无特别说明,文章将在合适的上下文中以“工具”指代“自定义Valgrind工具”;
  • 如无特别说明,文章提到的文件名及路径均为相对Valgrind源码的文件名及路径;
  • 文章将以mytool作为工具的名称,并以mt作为工具的“两字母缩写”(Valgrind官方文档要求一个工具要有两字母缩写);
  • 文章将以mytool作为存放工具的目录;
  • 文章将不对其所使用的反身代词“我们”和“我”做区分,且使用“我们”和“我”时没有特殊的含义(我也不知道我是谁);
  • 文章作者不会用automakeautoconf等工具;
  • 为了保护相关者的隐私,文章中(意外地或非意外地)提到的任何人名均为假名;
  • 文章的主要目的是作为备忘,以便在文章作者遭遇不可预料的意外时可以恢复其工作。所述“意外”包括但不限于相关资料的丢失、作者遗忘相关内容、作者身体停止工作;
  • 对于非作者本人,文章仅供参考,文章作者将不会对任何集体、组织或个人由于阅读此文章而造成的任何形式的损失负责。

获取和编译Valgrind源码

此步骤较为简单,不在此赘述。

创建空白自定义工具

下面将展示如何创建一个空白的Valgrind工具,并给出例子。

注册工具函数

根据Valgrind官方文档,一个工具必须向Valgrind核心(core)注册以下四个函数:

  1. void pre_clo_init():在Valgrind处理clo(command line options),此函数将进行工具的初始化工作,必须在这里向Valgrind核心注册工具的若干“detail”(名称、版本、描述等)。在此初始化函数中,还可以使用VG_(track_*)()宏注册若干事件监听器。可供注册的函数见include/pub_tool_tooliface.h
  2. void post_clo_init():在Valgrind处理clo(command line options),此函数将进行工具的初始化工作,用于根据命令行参数进行初始化工作。此函数在上述初始化函数中使用VG_(basic_tool_funcs)()宏注册。如不需要读取命令行参数,则此函数可以放空;
  3. 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
  4. 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 of date
==1472==

的输出即说明工具成功添加并运行。



# valgrind   # valgrind tool