所学,所得,所知
分类: LINUX
2016-11-04 11:34:03
移植GDB(3) init.c和target_ops v0.0
teawater
修改记录:
v0.0
2006-02-27,v0.0版本编写完成。没有对target_ops结构的每个元素进行详细介绍。
2006-02-07,文档创建。
目录
1.写在前面
2.GDB/gdb/init.c
2.struct target_ops
3.struct target_ops current_target
3.1.概述
3.2.本地调试接口的装载
1.写在前面
本文针对GDB-6.3进行编写。
下面是本文将使用的缩写:
GDBINT GDB Internals Manual的缩写。
GDB 指GDB源文件目录。
ARCH 体系结构名称。
TARGET 体系结构下的调试目标,一般是一种操作系统,比如Linux。
2.GDB/gdb/init.c
这个文件是在编译的时候动态生成的,具体生成的位置在/GDB/gdb/Makefile.in的1075行开始的代码,这个文件会在configure的时候作为模板生成/GDB/gdb/Makefile,那段生成init.c的代码就会在make的时候被调用。
这段生成init.c的代码主要的过程就是扫描所有编译中指定的库文件,比如指定在“移植GDB(1)”TARGET.mt文件和“移植GDB(2)”TARGET.mh文件的库文件,然后找出其中_initialize_NAME(后面的NAME可以是任意名称)为名称的函数,在init.c文件中生成一个函数initialize_all_files,对每个_initialize_NAME进行调用。
这个initialize_all_files函数将被GDB初始化函数GDB/gdb/top.c:gdb_init调用,也就是每次GDB初始化的时候都会对其进行调用。
所以库文件就可以通过包含一个_initialize_NAME名字的文件来进行一些初始化的操作,比如在“移植GDB(1)5.2”就介绍了在_initialize_ARCH_tdep函数中调用gdbarch_register函数注册gdbarch,下面将介绍的target_ops大部分也都是通过_initialize_NAME函数进行初始化和注册的。
2.struct target_ops
struct target_ops定义在GDB/gdb/target.h文件中,GDB中所有被调试的目标的控制和访问函数都被封装成这个结构,然后根据需要将结构装载到current_target上(后面会详细介绍),当GDB调试的时候直接对current_target结构中的函数指针进行调用就可以。比如GDB的模拟功能sim、远程调试功能remote以及本地调试接口ptrace、procfs等都以target_ops结构封装的。
大部分的target_ops结构都是先在前面介绍过的_initialize_NAME函数中进行初始化,然后调用函数GDB/gdb/target.c:add_target注册到列表GDB/gdb/target.c:target_structs上。
3.struct target_ops current_target
3.1.概述
这个结构就是GDB用来控制当前被调试目标的结构,当系统初始化(设置为dummy_target)、读入可执行文件(设置为exec_ops)或者执行target命令以后,就会调用GDB/gdb/target.c:push_target函数将需要的target_ops结构初始化到current_target上。当调用一些GDB命令的时候,则会调用current_target中的函数指针,也就对被调试目标进行了调试。
3.2.本地调试接口的装载
因为这个.本地调试接口的装载过程不是很直接,所以在这里对其进行一些介绍。
第一步,在GDB读入可执行文件的时候,会自动将GDB/gdb/exec.c:exec_ops装载到current_target上。
第一步,当运行运行run的时候会调用GDB/gdb/infcmd.c:run_command函数,在这个函数进行了一系列的分析处理后,最后会调用GDB/gdb/target.h:target_create_inferior宏,这个宏调用current_target.to_create_inferior,这里将调用注册在exec_ops上的函数GDB/gdb/target.c:find_default_create_inferior。
第二步,find_default_create_inferior函数首先调用函数GDB/gdb/target.c:find_default_run_target,在这个函数将通过前面介绍过的target_structs列表,扫描每个用add_target注册的target_ops结构。先检查这个target_ops结构有没有注册to_can_run函数指针,如果有对这个函数指针进行调用,一般来说本地调试结接口的target_ops结构都会注册这个函数指针,而且函数都会返回1,而非本地调试接口的target_ops结构则不会,所以都返回真的时候就记录这个target_ops结构在指针runable上,同时给count加1。
最后在扫描结束的时候检查count是否为1,不为1则报错,所以建议一个TARGET中只包含一个本地调试接口,最后返回runable。
第三步,然后调用这个返回的target_ops结构的to_create_inferior,这里会将这个调试接口的target_ops结构初始化到current_target上。比如在GDB/gdb/inftarg.c:child_create_inferior就调用了GDB/gdb/inftarg.c:ptrace_him,ptrace_him第一步工作就是调用push_target将deprecated_child_ops装载到current_target上。