| 個人檔案冒充另类相片部落格清單 | 說明 |
|
3/4/2006 移植GDB(4) gdbserver v0.0 (更新时间:2006-03-03)http://www.linuxforum.net/forum/showthreaded.php?Cat=&Board=program&Number=597734 附件中有txt版本 需要登陆后才能看见 移植GDB(4) gdbserver v0.0 teawater<teawater@gmail.com> 转载请标明来自 http://www.linuxforum.net 修改记录: v0.0 2006-03-03,v0.0版本编写完成。 struct target_ops没作详细介绍。 struct linux_target_ops的breakpoint_reinsert_addr介绍不是很清楚。 2006-03-01,文档创建。 目录 1.写在前面 2.整体结构描述 3.GDBSERVER/configure.srv 4.GDBSERVER/Makefile.in 5.GDB/gdb/regformats/reg-ARCH.dat 6.GDBSERVER/linux-ARCH-low.c 6.1.struct linux_target_ops the_low_target 6.2.struct regset_info target_regsets[] 1.写在前面 本文针对GDB-6.3进行编写。 gdbserver的移植是以完成gdbarch的移植为基础的,gdbarch的移植可以参见“移植GDB(1)”。 下面是本文将使用的缩写: GDBINT GDB Internals Manual的缩写。 GDB 指GDB源文件目录。 GDBSERVER 指GDBSERVER源文件目录GDB/gdb/gdbserver。 ARCH 体系结构名称。 TARGET 体系结构下的调试目标,一般是一种操作系统,比如Linux。 2.整体结构描述 gdbserver从程序结构的角度讲是独立于GDB本身的,在编译的时候也是需要单独编译的,但是因为其利用 到了GDB目录中的一些文件,所以不能单独发布。 GDBSERVER/server.c:main函数是gdbserver的核心部分,这个函数调用函数初始化gdbserver,跟远程的 GDB建立连接,对接到的GDBRSP控制包进行分析并调用相应的调试函数或者调试宏进行各种调试操作,然 后把调试信息返回。 每个调试函数和调试宏会根据需要调用注册在全局target_ops结构(这个结构跟GDB中的target_ops名称一 样,功能类似,定义在GDBSERVER/target.h中)GDBSERVER/target.c:the_target中的函数,这个全局变量 the_target是向下层不同的被调试目标提供的调试接口,其的初始化一般是在前面介绍的main函数调用的 函数initialize_low完成。 这个initialize_low就定义在下层接口文件中,在编译的时候选择合适的下层接口文件就可以实现相应的 支持。现有的gdbserver代码中只有一个用来支持Linux下ptrace方式调试的下层调试接口 GDBSERVER/linux-low.c。当然如果按照其结构编写,应该可以象GDB一样支持多种下层调试接口。 在函数GDBSERVER/linux-low.c:initialize_low中,比较主要的操作有: 调用GDBSERVER/target.c:set_target_ops将GDBSERVER/linux-low.c:linux_target_ops注册到 the_target上。linux_target_ops中的函数都会根据情况访问the_low_target结构中的函数和变量,这个 the_low_target是向每个ARCH提供的扩展接口,具体在下面介绍。 调用GDBSERVER/mem-break.c:set_breakpoint_data将the_low_target中声明的断点和断点长度设置到全 局变量中去,其将在gdbserver本身需要设置断点的时候使用。 调用init_registers函数初始化寄存器信息,这个函数是在编译的时候生成的,将在后面介绍其的生成过 程。 the_low_target是在linux-low.c中为了方便其支持多个ARCH而定义的linux_target_ops结构的接口, linux_target_ops声明在GDBSERVER/linux-low.h文件中。在GDBSERVER目录中,有几个linux-ARCH-low.c 文件,每个文件中都有一个the_low_target结构。在编译的时候只要选择合适的linux-ARCH-low.c文件一 起编译,就可以支持相应的ARCH。 3.GDBSERVER/configure.srv 这个文件将被GDBSERVER/configure调用,其的作用是根据前面程序分析得到的${target}也就是当前的 TARGET,设置一些编译的选项。文件的结构很简单,就不作详细介绍了,就介绍一下需要设置的选项: srv_regobj= 这是一个必须设置的选项,其标明了当前需要连接到gdbserver中的寄存器库文件也就是包含 init_registers函数的库文件,后面将介绍这个库文件如何生成。 srv_tgtobj= 这是一个必须设置的选项,其标明了当前需要连接到gdbserver中的跟要编译TARGET相关的库文件,一般 来说是linux-low.o(由前面介绍过的linux-low.c生成)和linux-ARCH-low.o(由前面介绍过的linux-ARCH -low.c生成),注意多个文件用分号包起来。 srv_linux_usrregs=yes 这是一个选择设置的选项,当设置了这个选项的时候,configure将检查当前TARGET的ptrace系统调用是 否支持PTRACE_POKEUSER和PTRACE_PEEKUSER,如果支持编译的时候将设置宏HAVE_LINUX_USRREGS。 srv_linux_regsets=yes 这是一个选择设置的选项,当设置了这个选项的时候,configure将检查当前TARGET的ptrace系统调用是 否支持regset相关的几个参数,如果支持编译的时候将设置宏HAVE_LINUX_REGSETS。 注意srv_linux_usrregs选项和srv_linux_regsets选项至少要设置一个,否则linux-low.c中的读取被调 试程序目标的函数将无法正常编译。 srv_linux_thread_db=yes 这是一个选择设置的选项,当设置了这个选项的时候,configure将检查当前TARGET是否支持 libthread_db这个用来调试多线程程序的库,如果支持编译的时候将设置宏HAVE_THREAD_DB_H。 4.GDBSERVER/Makefile.in 这是configure的时候用来生成Makefile的模板,如果需要加入新的TARGET也需要对这个文件进行修改。 SFILES= 在这个项目最后加入新的TARGET增加的.c文件,不过这个项目更编译gdbserver并没什么关系,是给etags 使用的。 linux-ARCH-low.o: linux-ARCH-low.c $(linux_low_h) $(server_h) 这里是生成前面srv_tgtobj=标出的.o文件的Makefile语句,后面会介绍这个.c文件如何编写。 reg-ARCH.o : reg-ARCH.c $(regdef_h) reg-ARCH.c : $(srcdir)/../regformats/reg-ARCH.dat $(regdat_sh) sh $(regdat_sh) $(srcdir)/../regformats/reg-ARCH.dat reg-ARCH.c 这里是生成前面srv_regobj=标出的.o文件的Makefile语句,用户要编写的文件是reg-ARCH.dat,后面会 介绍。 5.GDB/gdb/regformats/reg-ARCH.dat 这个文件是用来标明某个ARCH的寄存器信息。 name:ARCH 第一行写ARCH的名称。 expedite:name1,name2,name3 这里表明的几个寄存器名称name1,name2,name3是在其后面声明的,在gdbserver向GDB用T停止包(具体信 息见Debugging with GDB: Remote Protocol D.3 Stop Reply Packets)返回信息的时候,包中将包括这 里指出的几个寄存器。当gdbserver向GDB发送停止包的时候,GDB通常需要取得当前pc,sp等几个寄存器 的值来确定被调试程序所在位置等信息,如果返回包没包含这些信息其就需要再发包请求,所以通常在T 停止包中会包含几个寄存器的值,这里就是用来指出哪些寄存器将出现在T停止包中的,一般来说是pc, sp,bp等几个寄存器。 bit_num:name 这里指出每个寄存器的位数和名称,前面的bit_num是寄存器的位数,32位就是32,64位就是64。后面的 name写成寄存器的名称。有多少寄存器就写多少行。 6.GDBSERVER/linux-ARCH-low.c 6.1.struct linux_target_ops the_low_target 这个文件最主要的部分就是声明struct linux_target_ops the_low_target,并初始化其中内容,这个变 量在前面介绍过,其中的函数和变量会被linux-low.c中的函数调用,现在来介绍一下这个结构中每个元 素: int num_regs; 这个变量用来标明寄存器的数量。 int *regmap; 一般会让这个指针指向一个int类型的数组,这个数组的第n个元素的值是第n个寄存器的值在user结构(这 个结构的介绍见“移植GDB(2)”)中的偏移,如果值设置为-1则表示这个寄存器的值在user结构中不存在 。 int (*cannot_fetch_register) (int); 注册在这个指针上的函数会判断参数指定序号的寄存器是否可以读取,如果不可以则返回真。 int (*cannot_store_register) (int); 注册在这个指针上的函数会判断参数指定序号的寄存器是否可以设置,如果可设置但是如果设置失败就报 错返回0,如果不可设置返回1,如果可设置且设置失败不用报错返回2。 CORE_ADDR (*get_pc) (void); 注册在这个指针上的函数用来取得被调试程序的PC。 void (*set_pc) (CORE_ADDR newpc); 注册在这个指针上的函数用来设置被调试程序的PC为newpc。 const char *breakpoint; 这个指针指向当前TARGET支持的断点内容。 int breakpoint_len; 这个变量用来标明断点的长度。 CORE_ADDR (*breakpoint_reinsert_addr) (void); 如果当前的TARGET的ptrace支持PTRACE_SINGLESTEP也就是硬单步,则将这个函数指针设置为NULL就可以 ;如果不支持,设置在这个指针上的函数将当前被调试程序所在的函数的返回值返回,在RISC CPU中通常 都有一个返回地址寄存器,直接取出这个寄存器的值返回就可以了。 int decr_pc_after_break; 因为某些ARCH被断点中断后取得的PC值并不是被中断的值,所以需要减去这个值取得实际的被中断时候的 地址。 int (*breakpoint_at) (CORE_ADDR pc); 注册在这个指针上的函数先取得指定地址pc上的内存,然后判断是否是从GDB设置过来的断点,如果是则 返回真。 6.2.struct regset_info target_regsets[] 如果在前面介绍过的GDBSERVER/configure.srv中设置了srv_linux_regsets=yes选项,也就是说有可能设 置了HAVE_LINUX_REGSETS的时候,需要在linux-ARCH-low.c中包含target_regsets结构数组。 这个数组中的变量和函数指针将被GDBSERVER/linux-low.c文件中的regsets_fetch_inferior_registers 函数和regsets_store_inferior_registers函数使用,这两个函数将使用ptrace系统调用regset直接取得 寄存器的信息。 这个数组一般来说是有几个类型的寄存器就需要设置几个元素,一般的TARGET都是定义2个元素普通寄存 器和浮点寄存器,i386在有扩展浮点寄存器的时候会定义3个比上面多一个扩展浮点寄存器。 struct regset_info定义在GDBSERVER/linux-low.h中,现在来介绍一下regset_info结构中的每个元素: int get_request, set_request; 这两个参数是给ptrace用的读寄存器信息和写寄存器信息用的参数,一般来说普通寄存器就是 PTRACE_GETREGS和PTRACE_SETREGS,浮点寄存器就是PTRACE_GETFPREGS和PTRACE_SETFPREGS,扩展浮点寄 存器(i386常见)就是PTRACE_GETFPXREGS和PTRACE_SETFPXREGS。 int size; 取得和设置寄存器信息的长度,一般来说普通寄存器是sizeof (elf_gregset_t),浮点寄存器是sizeof (elf_fpregset_t),扩展浮点寄存器(i386常见)就是sizeof (elf_fpxregset_t)。 enum regset_type type; 分为三种类型:GENERAL_REGS,普通寄存器;FP_REGS,浮点寄存器;EXTENDED_REGS,扩展浮点寄存器。 regset_fill_func fill_function; 注册在这个指针上的函数的作用是依次用GDBSERVER/regcache.c:collect_register函数读出每个当前对 应类型寄存器的值转化为相应的regset结构并将其存到参数BUF相应位置中。 regset_store_func store_function; 注册在这个指针上的函数的作用是依次用GDBSERVER/regcache.c:supply_register函数将参数BUF中的 regset结构的寄存器信息读出并存到相应的寄存器缓冲中。 注意在使用target_regsets的同时文件要包含GDB_GREGSET_T和GDB_FPREGSET_T的定义,一般编写为: #define GDB_GREGSET_T elf_gregset_t #define GDB_FPREGSET_T elf_fpregset_t 回應 (3)
引用通告此內容的引用通告是: http://teawater.spaces.live.com/blog/cns!48DDFFCE89F7F319!1358.trak 引述這則內容的部落格
|
|
|