[转]GDBINT gdb internal Notes …

Adding a New Target

为了建立一个target,需要添加以下文件:

gdb/config/arch/ttt.mt

      makefile,定义 `TDEPFILES=...' and `TDEPLIBS=...'. 指定`TM_FILE= tm-ttt.h':描述tty的头文件. 

 

 


gdb/ttt-tdep.c  或许根本就不需要这个文件.如果 `tm-ttt.h' 太复杂,可以把函数放到这里

 


gdb/arch-tdep.c 
gdb/arch-tdep.h registers, stack ...的描述, it is included by `ttt-tdep.h'.

 

gdb/config/arch/tm-ttt.h `tm.h'是这个文件的一个link,configure自动创建,registers, stack frame format instructions描述.新的target不应该使用这个文件了.

 

`gdb/config/arch/tm-arch.h' 新target无需此文件了. 同cpu的target可以共享.

如果是为一个新的os添加支持(cpu已存在),则只需要添加 `config/tm-os.h' ,描述此os的特殊facilities即可,比如extra symbol table info; the breakpoint instruction needed; 等等),然后写一个 `arch/tm-os.h',就include`tm-arch.h'和config/tm-os.h即可.


Target Descriptions  通过上一个章节,可以对target的各种特性有一个大致了解:寄存器,地址和指针,stack frame ...
Target Descriptions Implementation

  GDB 连接到一个new target之前,恢复成一个默认的target,连接完成后,通过 target_find_description 找到新的target. 新的target可以由用户指定的XML文件来获取,或者远程的qXfer:features:read (also XML), 或者在target vector里定制的to_read_description函数来获取target.比如远程的target支持判断一个MIPS target是32-bit还是64-bit(根据 `g' packet的大小).


  发现一个target description后,GDB 通过gdbarch_update_p创建新的gdbarch. 优先根据 `<architecture>'来确定调用那个 gdbarch initialization 函数.然后,调用初始化函数,初始化函数可以调整这个architecture:比如通过to_read_description确定属性集.


Adding Target Described Register Support

Target descriptions通过体系特定的支持函数,可以报告更多的寄存器到target.

一个target description或者没有寄存器,或者有完整的寄存器集.

如果 tdesc_has_registers 返回1, 代表这个description包含寄存器,architecture's gdbarch_init函数应该完成如下功能:

 

  • 通过tdesc_data_alloc 分配内存(在搜索匹配的gdbarch后者分配新的之前进行)

     

  • 通过tdesc_find_feature,根据name确定标准属性集.

     

  • 通过tdesc_numbered_register 和 tdesc_numbered_register_choices 确定standard features需要的registers.

     

  • 如果需要的feature缺失,返回NULL, 如standard feature缺失必要寄存器,返回NULL.

     

  • 释放分配的数据,除非调用了tdesc_use_registers.

     

  • Call set_gdbarch_num_regs as usual, with a number higher than any fixed number passed to tdesc_numbered_register.

     

  • 返回新创建的gdbarch之前,调用 tdesc_use_registers.

     

调用tdesc_use_registers后, 这个architecture的register_name, register_type, 和 register_reggroup_p routines将不会被调用;这些信息将从target description获取. num_regs 或许增加,因为可能有新的寄存器加进来.

Pseudo-registers require some extra care:

 

  • Using tdesc_numbered_register allows the architecture to give constant register numbers to standard architectural registers, e.g. as an enum in `arch-tdep.h'. But because pseudo-registers are always numbered above num_regs, which may be increased by the description, constant numbers can not be used for pseudos. They must be numbered relative to num_regs instead.

     

  • The description will not describe pseudo-registers, so the architecture must call set_tdesc_pseudo_register_name, set_tdesc_pseudo_register_type, and set_tdesc_pseudo_register_reggroup_p to supply routines describing pseudo registers. These routines will be passed internal register numbers, so the same routines used for the gdbarch equivalents are usually suitable.
下面是一个pseudo-register的例子:

http://sourceware.org/ml/gdb-patches/2000-07/msg00127.html


Target Vector Definition  target vector 定义GD对target system的抽象接口.GDB 包含30-40这样的接口,但每个configuration只有几个.
Managing Execution State

  target vector 状态:

completely inactive :not pushed on the target stack

active but not running:pushed, but not connected to a fully manifested inferior

completely active (pushed, with an accessible inferior).

persistent connections to a target even when the target has exited or not yet started.如:

使用target sim连接到simulator是,并不创建进程,寄存器和内存在run前都不可访问.类似的, kill之后,程序也不能继续运行.但是这两种情况下GDB仍然连接到simulator.

如果target仅仅支持complete activation,则在其to_open函数中,应该使用push_target将自己压入堆栈(rfc), 在其to_mourn_inferior函数中通过unpush_target将自己出栈.

如果target支持partial和complete activation,就不应该在to_mourn_inferior中出栈(但是仍然需要在to_open中入栈),而应调用 target_mark_running或者target_mark_exited. 只要任何时候inferior fully active就应该调用target_mark_running(如在to_create_inferior和to_attach中), 而inferior inactive(to_mourn_inferior)时就掉用 target_mark_exited.在to_kill中,应该调用target_mourn_inferior确保target进入inactive 状态.



Existing Targets

 

File Targets

executables 和 core files 都有target vectors.

 


Standard Protocol and Remote Stubs

GDB 文件remote.c 通过串口和target system通讯.GDB 提供一系列的stubs: stub集成到target系统中作为GDB的通讯断点.其名称一般是*-stub.c. 

  GDB user's manual 描述如何将stub嵌入target中:下面的例子讨论集成SPARC stub 到操作系统:

stub中的trap处理代码假设trap_low的接口如下:

 

  1. %l1 和 %l2 分别包含pc 和 npc;

     

  2. traps 以禁止;

     

  3. 已经在正确的trap window(rfc).

满足以上条件时,可以从hw trap vector直接跳到stub.一般情况下stub使用的trap,操作系统是不使用的(一般是不可恢复性错误),也没有共享问题(有也可以支持). 最重要的trap之一ta 1(rfc):用于单步执行或者breakpoint.

这里有个remote stub的参考文档:
http://sca.uwaterloo.ca/coldfire/gcc-doc/docs/porting_4.html 



Native Debugging

 

如下文件控制native support的配置:

 

`gdb/config/arch/xyz.mh' makefile. 通过NATDEPFILES 列出所有体系相关的.o文件 . 通过NAT_FILE= nm-xyz.h指定native support的头文件.其他可选项:`NAT_CFLAGS', `NAT_ADD_FILES', `NAT_CLIBS', `NAT_CDEPS'参考`Makefile.in'.

 

`gdb/config/arch/nm-xyz.h' `nm.h' 是到此文件的一个link(configure 自动创建). 包含C的宏定义,描述native system环境,如child process control和core file.

 

`gdb/xyz-nat.c' native support的C代码.(有些系统都没有这个).

许多通用函数可以为很多系统共享,如果你的系统可以使用这些函数,使用NATDEPFILES定义所需要的.o即可.否则,你需要重新实现这些函数,并放到xyz-nat.c中.

`inftarg.c' 包含  target_ops vector  ,支持通过ptrache和wait的Unix child processes.

 

`procfs.c'  target_ops vector  支持通过/proc控制Unix child processes.

 

`fork-child.c' unix形式的fork和exec创建子进程.

 

`infptrace.c' 采用unix ptrace接口的被调试程序控制. 
Native core file Support

 

`core-aout.c::fetch_core_registers()' 读取corefile的registers. 此函数调用register_addr(). GDB使用BFD读取core file, 事实上,所有machines都应该使用 core-aout.c, 仅提供fetch_core_registers 即可(xyz-nat.c,or REGISTER_U_ADDR in nm-xyz.h).

 

`core-aout.c::register_addr()' 如果nm-xyz.h file中定义了REGISTER_U_ADDR(addr, blockend, regno), 其功能应该如下:将addr设置成'user' struct中GDB寄存器regno的偏移. blockend 是'upgae'(u.u_ar0)内的偏移.如果定义了 REGISTER_U_ADDR , `core-aout.c' 会定义register_addr() 函数,并使用这个宏.如果没有定义此宏,但是又要使用fetch_core_registers(), 则必须自己定义 register_addr(), 并置于xyz-nat.c  如果自己定义了fetch_core_registers(), 就不用把register_addr()单独拿出来定义了.

当 在一个新的OS上运行GDB native时,为了确保能够调试core file,就要写代码支持解析这个OS的core file,或者修改`bfd/trad-core.c'. 首先,定义一个寄存器结构来描述OS Core file中的寄存器(比如core file 的u-area),将定义core file header的头文件包含进来(u-area or a struct core). 然后,修改trad_unix_core_file_p 使用这些信息建立core file总的data segment, stack segment和其他段的信息(shared library ,control information), 以及"registers" segment(如果有两组寄存器,比如integer和float),即 "reg2" segment. 这些section 的信息使BFD知道如何从corefile读取这些信息. 然后,修改GDB:定义fetch_core_registers,使用通用的core-aout.c,或者自己的`xyz-nat.c'. GDB使用这个函数来将寄存器的值转移到GDB的"registers" array中.

   如果你的系统使用`/proc'控制进程,并使用ELF format的core files,则可以使用相同的函数来读取进程和core file的寄存器.



 

Native Conditionals

`nm-system.h'中可能存在的configure:

 

CHILD_PREPARE_TO_STORE  If the machine stores all registers at once in the child process, then define this to ensure that all values are correct. This usually entails a read from the child.

[Note that this is incorrectly defined in `xm-system.h' files currently.]

 

FETCH_INFERIOR_REGISTERS  如果自己定义fetch_inferior_registers 和 store_inferior_registers ,定义此宏.否则`infptrace.c'将编译进来.

 

int gdbarch_fp0_regnum (gdbarch)  返回首个浮点寄存器的编号.

 

int gdbarch_get_longjmp_target (gdbarch)  在ECstation和Iris中,这个是一个native-dependent的参数,大多数系统是target dependnet的.此函数确定longjmp将要跳转到的PC地址,(假定我们正好停在一个longjmp brakpoint中).(see GDBINT)

 

I386_USE_GENERIC_WATCHPOINTS An x86-based machine can define this to use the generic x86 watchpoint support; see I386_USE_GENERIC_WATCHPOINTS.

 

ONE_PROCESS_WRITETEXT  定义此宏后,如果breakpoint插入失败,警告用户另一个进程可能使用同一个executable.

 

PROC_NAME_FMT  定义一个/proc 设备的name格式.定义在`nm.h',覆盖`procfs.c'中的默认定义.

 

SHELL_COMMAND_CONCAT  启动inferior时,将此字符串作为shell 命令的前缀.

 

SHELL_FILE  使用这个shell去启动inferior,默认是"/bin/sh".

 

SOLIB_ADD (filename, from_tty, targ, readsyms)  用于取filename中的symb到GDB的 symbol table.如果 readsyms是0,symbols将不读入,但是其他处理照常进行.

 

SOLIB_CREATE_INFERIOR_HOOK (rfc)  Define this to expand into any shared-library-relocation code that you want to be run just after the child process has been forked.

 

START_INFERIOR_TRAPS_EXPECTED  一般GDB启动一个inferior时, 又两次trap:因此shell运行时,一次program 自己运行时.如果实际上不是2次,定义此宏为正确的值.

 

CLEAR_SOLIB  See `objfiles.c'.

 

 



Support Libraries BFD

 

identifying executable and core files

 


access to sections of files  BFD 解析文件头,确定像.text .data这些section 的名字,虚拟地址,大小等.

 

specialized core file support  BFD 提供函数用于确定core file的failing signal,以及此core file是否匹配一个特定的可执行文件.

 

locating the symbol information  opcodes

广泛用于binutils.提供反汇编支持.

readline  command line编辑.

libiberty

此库提供一系列的函数用于补足,替换和扩展操作系统提供的功能.GDB使用很多这个库提供的特性:如 C++ demangler,IEEE floating format support, 输入选项解析`getopt', `obstack'扩展等.


obstacks in GDB

 obstack 是一个内存分配和释放机制.每个 obstack 是一个内存池,操作方式类似堆栈. 内存以LIFO方式在obstck上分配和释放.

主要用于object files管理. 每个obj文件有一个对应的obstack,许多对象在obstack上分配:....(略)

 在不同时间分配的对象,一次性的释放.

 

gnu-regex

Regex conditionals. 

 

 


Array Containers

see `vec.h' (略)

例子:

DEF_VEC_P(tree); // non-managed tree vector.

struct my_struct {
VEC(tree) *v; // A (pointer to) a vector of tree pointers.
};

struct my_struct *s;

if (VEC_length(tree, s-&gt;v)) { we have some contents }
VEC_safe_push(tree, s-&gt;v, decl); // append some decl onto the end
for (ix = 0; VEC_iterate(tree, s-&gt;v, ix, elt); ix++)
{ do something with elt }
其他接口函数:

 

 


 


 


 


 


VEC_length  VEC_empty VEC_last  ....

 

Coding
Cleanups

Cleanups 是GDB使用的一个通用机制.cleanup 会在以后的合适时间执行:命令完成,error处理等.

使用方式:

struct cleanup *old_chain;

     Declare a variable which will hold a cleanup chain handle.

 

old_chain = make_cleanup (function, arg); Make a cleanup which will cause function to be called with arg (a char *) later. The result, old_chain, is a handle that can later be passed to do_cleanups or discard_cleanups. Unless you are going to call do_cleanups or discard_cleanups, you can ignore the result from make_cleanup.

do_cleanups (old_chain); Do all cleanups added to the chain since the corresponding make_cleanup call was made.

discard_cleanups (old_chain); Same as do_cleanups except that it just removes the cleanups from the chain and does not call the specified functions. 细节请参考GDBINT.

Per-architecture module data

向gdbarch 添加module specific per-architecture data-pointers的机制:(see GDBINT)

Function:  struct  gdbarch_data  *gdbarch_data_register_pre_init (gdbarch_data_pre_init_ftype *pre_init)  pre_init is used to, on-demand, allocate an initial value for a per-architecture data-pointer using the architecture's obstack (passed in as a parameter). Since pre_init can be called during architecture creation, it is not parameterized with the architecture. and must not call modules that use per-architecture data.

Function:  struct  gdbarch_data  *gdbarch_data_register_post_init (gdbarch_data_post_init_ftype *post_init)  post_init is used to obtain an initial value for a per-architecture data-pointer  after. Since post_init is always called after architecture creation, it both receives the fully initialized architecture and is free to call modules that use per-architecture data (care needs to be taken to ensure that those other modules do not try to call back to this module as that will create in cycles in the initialization call graph).

These functions return a struct gdbarch_data that is used to identify the per-architecture data-pointer added for that module.

The per-architecture data-pointer is accessed using the function:

Function:  void  *gdbarch_data  (struct gdbarch *gdbarch, struct gdbarch_data *data_handle)  Given the architecture arch and module data handle data_handle (returned by gdbarch_data_register_pre_init or gdbarch_data_register_post_init), this function returns the current value of the per-architecture data-pointer. If the data pointer is NULL, it is first initialized by calling the corresponding pre_init or post_init method. 
Wrapping Output Lines

输出换行的标准. 细节参考GDBINT.



GDB Coding Standards以下部分请参考GDBINT.

ISO C

GDB assumes an ISO/IEC 9899:1990 (a.k.a. ISO C90) compliant compiler.

GDB does not assume an ISO C or POSIX compliant C library.

 

Memory Management

GDB does not use the functions malloc, realloc, calloc, free and asprintf.

GDB uses the functions xmalloc, xrealloc and xcalloc....


Compiler Warnings  Formatting  Comments C Usage

Function Prototypes  Internal Error Recovery File Names Include Files Clean Design and Portable Implementation

 GDB多年的经验告诉我们许多可移植性方面的问题:不能假定任何target的byte order(values, object files, and instructions).必须使用SWAP_TARGET_AND_HOST宏. 

所有操作target的函数必须使用 target_ops vector. 不能假定host和target是同一台机器(除了native),尤其不能假定target机器的头文件可以在host上使用.

more detail see GDBINT


Porting GDB

在新的machine上编译GDB需要很多配置工作,需要修改许多头文件和配置脚本.假定新的host是xyz (e.g., `sun4'), 其配置名是 arch-xvend-xos (e.g., `sparc-sun-sunos4') :

 

  • 在根目录,编辑 `config.sub' 添加 arch, xvend, and xos 到architecture列表.添加xyz作为arch-xvend-xos的别名.运行以下命令测试修改:
    ./config.sub xyz
    ./config.sub arch-xvend-xos
    (或许需要port BFD)
  • 配置GDB:编辑`gdb/configure.host'时期认识你的系统,设置 gdb_host 为 xyz, 编辑`gdb/configure.tgt',设置gdb_target为合适值,如xyz.
  • 最后,开始写对应的host-, native-,  target-dependent的 `.h' 和 `.c' 文件.......(不少啊).

 


Other

为完整性,以下部分没有阅读,这些部分描述GDB的代码配置管理部分内容,以及代码阅读的一些提示:

16. Versions and Branches

17. Start of New Year Procedure

18. Releasing GDB

19. Testsuite

20. Hints

A. GDB Currently available observers

B. GNU Free Documentation License


转自:http://hi.baidu.com/systemsoftware/blog/item/7b33333d69cf9e0ebba16772.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值