2007-12-30
GDBINT gdb internal Notes
GDB结构简介(overall structure)
1)GDB组成:
user interface
symbol handling (the symbol side)
object file readers, debugging info interpreters, symbol table
management, source language expression
parsing,type and value printing.
target system handling (thetarget side).
execution control, stack frame analysis, and physical target
manipulation
target side 和symbol side的区分并不是非常清晰,只是对于理解GDB大有好处.
2)GDB Configurations
Host/host surport/host dependent:host
是运行GDB的系统,为了让GDB在host上运行所需要的信息(#include/宏定义/...)
叫做host surpot.
Target/Target surport/target dependent: 就是目标机/目标进程的堆栈结构,指令集,寄存器...
Native/native surport/native dependent: host和target是一样的,这是候需要的支持叫做native
dependent.比如unix下需要的
子进程支持/通过ptrace、procfs对进程调试的支持/如何在这种情况下获得target的寄存器内存信息等.
3)目录结构和文件命名原则
*read.c :读取obj/symbol table/ *-thread.c :处理debug thread的文件 inf*.c : 处理 inferior program的代码 (被调试程序的幽默叫法)
*-tdep.c : target dependent code *-nat.c : native surport code
Algorithms
GDB采用的算法不是很复杂,关键在于很容易迷失在具体的细节/特殊情况(和OS面临的处境差不多).
Frame
GDB 为了支持DWARF标准的Call Frame而重新定义了GDB自己的Frame结构.GDB的Frame用于跟踪calling
和called 函数.就是一个调用
栈的back trace过程.GDB 的Frame不仅仅是个call
frame,每级frame都包含当前cpu状态的snapshot(或可以取到)(fix me).
sentinel frame:当前指令的frame,调用栈的顶端,level是-1,类型是SENTINEL_FRAME,而当前函数的frame(fix
me)其level是0.
unwind操作:取自DWARF标准, frame_register_unwind,就是返回上一级frame.
Prologue Analysis
CFI : Dwarf call frame information,现在的GCC都生成这种call frame 信息了.
Prologure 分析用于找出frame的size和older
frame的基地址.虽然有CFI的帮助会简单些,但是不是什么时候都有CFI的.并且
Prologue分析这个技术早于CFI. 这种back trace容许GDB修改一些参数或者一个某些变量的值. 应为有callee saved
register存在,所
以,进程的frame pointer会发生改变.并且某些变量可能无规则的散布于yongest的frame中.(request comments)
Prologure技术的基本原理是分析具体的汇编码,藉此找出这些frame size和这些保存在stack frame中的寄存器值.prologue-value.h prologue-value.c提供了一个prologue分析的框架,从函数的入口指令开始,分析到的当前PC, 然后: 1)检查sp值是否可知:知道了,意味着得到了frame size. 2)检查我们吧previous的frame指针存在哪里.
具体的细节请参考GDBINT 和相关代码(request comments).
Breakpoint HandlingHardware Breakpoint:
需要CPU的支持.执行到指定PC就break out(一个中断或者其他什么机制).
Software Breakpoint: GDB把指定地址的指令换成一条特殊指令(比如x86可以是int3,可以是div
0),等异常发生后GDB获取控制权,等到
user 发出继续的命令后,再把那条指令换回去.
软件break point的宏定义:BREAKPOINT
breakpoint的处理大多在 `breakpoint.c',`infrun.c'.
接口函数简介:
target_remove_breakpointtarget_insert_breakpoint (bp_tgt)
target_remove_hw_breakpoint (bp_tgt)target_insert_hw_breakpoint (bp_tgt)
Longjmp Support
GDB支持在在程序做longjmp的时候break在longjmp的目标地址. (参考 "maint info
breakpoint").必须实现
gdbarch_get_longjmp_target.同时jmp_buf是系统特定的,应该在tm-target.h中定义jmp_buf.参考tm-sun4os4.h sparc-tdep.c
Watchpoints就是数据访问时的breakpoint.GDB总是试图使用hw支持的watchpoints.
但是并不是所有系统都有watch point支持,或者hw资源不够,或
者要监视的内存太大...
software的watchpoint是非常慢的:采用单步执行,每次检查目标地址.对于write
watch,gdb就是比较watch地址的值.对于read watch
point,需要目标系统提供target_stopped_data_address:返回被调试程序停止时,所访问的地址. 下面是支持硬件Watchpoints的一些资源: TARGET_HAS_HARDWARE_WATCHPOINTS
If defined, the target supports hardware watchpoints.
TARGET_CAN_USE_HARDWARE_WATCHPOINT (type, count, other)
Return the number of hardware watchpoints of type type that
are possible to be set.
The value is positive if count watchpoints of this type can
be set, zero if setting watchpoints of this type
is not supported, and negative if count is more than the
maximum number of watchpoints of type type that can
be set. other is non-zero if other types of watchpoints are
currently enabled (there are architectures which
cannot set watchpoints of different types at the same time).
-
TARGET_REGION_OK_FOR_HW_WATCHPOINT (addr, len) - Return non-zero if hardware watchpoints can be
used to watch a region whose address is addr and whose
length
- in bytes is len.
target_insert_watchpoint (addr, len, type)
target_remove_watchpoint (addr, len, type) - Insert or remove a hardware watchpoint
starting at addr, for len bytes.
type is the watchpoint type, one of the
- possible values of the enumerated data type
target_hw_bp_type, defined by
`breakpoint.h' as follows:
enum target_hw_bp_type { hw_write = 0, /* Common (write) HW watchpoint */ hw_read = 1, /* Read HW watchpoint */ hw_access = 2, /* Access (read or write) HW watchpoint */ hw_execute = 3 /* Execute HW breakpoint */ };
-
These two macros should return 0 for success, non-zero for failure.
target_stopped_data_address (addr_p) - If the inferior has some watchpoint that
triggered, place the address associated with the watchpoint at the
location pointed to by addr_p and return non-zero.
Otherwise, return zero. Note that this primitive is used by GDB only
ontargets that support data-read or data-access type watchpoints, so
targets that have support only for data-write watchpoints need not
implement these primitives.
HAVE_STEPPABLE_WATCHPOINT - If defined to a non-zero value, it is not
necessary to disable a watchpoint to step over it.
int gdbarch_have_nonsteppable_watchpoint (gdbarch) - If it returns a non-zero value, GDB should
disable a watchpoint to step the inferior over it.
HAVE_CONTINUABLE_WATCHPOINT - If defined to a non-zero value, it is possible
to continue the inferior after a watchpoint has been hit.
CANNOT_STEP_HW_WATCHPOINTS - If this is defined to a non-zero value, GDB
will remove all watchpoints before stepping the inferior.
STOPPED_BY_WATCHPOINT (wait_status) - Return non-zero if stopped by a watchpoint.
wait_status is of the type
struct target_waitstatus, defined by `target.h'. Normally,
this macro is defined to invoke the function pointed to by the to_stopped_by_watchpoint
member of the structure(of the type target_ops, defined on `target.h') that
describes the target-specific operations; to_stopped_by_watchpoint ignores the
wait_status argument.
GDB does not require the non-zero value returned by STOPPED_BY_WATCHPOINT to be 100%
correct, so if a target cannot determine for sure whether the
inferior stopped due to a watchpoint, it could return non-zero "just
in case".
x86 Watchpoints :请参考 GDBINT英文原版.
Checkpoints
Checkpoints是一个程序运行状态的一个副本. 以后可以从这里重新开始执行. 实现方式有fork一个子进程,
保持core文件等.总之要保存
程序状态的一切:寄存器/内存/....
- Observing changes in GDB internals (眼拙,未能明白讲的是啥)
.....算了吧这个没有太大必要看了. 同时 libgdb
也不看了:没啥详细说明,是个GDB的标准库,用于构建图形化的user界面等.
Symbol Handling
这是个关键模块. Symbol包括函数,变量和类型.
Symbol Reading
symfile.c 含有打开synbol
file的代码.(参考GDB命令symbol-file命令,一般就在要调试的程序中).GDB也使用BFD来读取符号表:参考 find_sym_fns.
Symbol-reading modules 通过add_symtab_fns向GDB注册自己,其参数是struct sym_fns:symbol format的名称,
prefix的长度, 四个函数指针.
每个symbol reading模块提供下面四个接口函数:(细节参考GDBINT或者代码)(现在还不是很清楚,request
comments).
xyz_symfile_init(struct sym_fns *sf)
-
当需要读取符号表的时候,symbol_file_add 会调用此函数,参数是新分配的一个fym_fns,其bfd
field 是新符号表对应的BFD.
xyz_new_init() -
放弃当前的symbols时,symbol_file_add 调用此函数.
xyz_symfile_read(struct sym_fns *sf, CORE_ADDR addr, int mainline) -
symbol_file_add 调用此函数获取具体的符号表:psymtabs or symtabs. sf 是调用初始化函数时的那个sym_fns.
xyz_psymtab_to_symtab (struct partial_symtab *pst)
- Partial Symbol
Tables
GDB 有三种符号表:
-
Full symbol tables (symtabs) :包含关于符号和地址的主信息.
-
Partial symbol tables (psymtabs):包含足够的信息去读取full symbol table.
-
Minimal symbol tables (msymtabs):非调试用symbols.
psymtab 的作用是快速传递一个程序的符号表信息:external symbols,types, static symbols and
types, enum values declared at file scope.psymtab还包含一些地址范围.
psymtab的使用方式如下:
1)通过一个指令地址,可以找到psymtable的一个地址范围,从而可以读取完整的符号表.比如find_pc_function, find_pc_line, and other
find_pc_...
2)通过名字来使用psymtab: lookup_symbol, 通过名字找到对应的完整符号.
psymtab不含有符号的类型信息. 细节请参考GDBINT.
Types
Fundamental Types (e.g., FT_VOID, FT_BOOLEAN).
GDB使用的内部类型.
Type Codes (e.g., TYPE_CODE_PTR, TYPE_CODE_ARRAY).
属于基本类型或者派生类型. 典型情况下几个基本类型 FT_* 映射到一种TYPE_CODE_* ,
通过其bit长度,是否是signed的等熟悉进行区分.
Builtin Types (e.g., builtin_type_void, builtin_type_char).
历史原因造成的,对应于基本类型.(GDB的维护人员其实打算把这些internal type给搞掉的: builtin_type_int (gdbtypes.c)基本上和 a TYPE_CODE_INT
(c-lang.c)是一样的.(对应于FT_INTEGER).区别在于builtin_type 不和任何objfile有关联,而`c-lang.c' 则搞了很多 TYPE_CODE_INT, 每个都和特定的objfile相关.
Object File Formats
a.out
: unix的原始的obj文件类型. 符号表几乎没有,对应文件是dbxread.c.
COFF format : System V Release 3 (SVR3) Unix,
符号表有缺陷(比如include的头文件不能解析),对应文件coffread.c
ECOFF : COFF
扩展版本,Mips and Alpha workstations, mipsread.c
XCOFF : IBM
RS/6000 running AIX
PE
: Windows 95 and NT use, 基本上是COFF.
ELF
: System V Release 4 (SVR4) Unix. ELF 类似COFF但是解决了COFF的许多不足, elfread.c
SOM :
HP(not to be confused with IBM's SOM, which is a cross-language
ABI),`somread.c'.
Debugging File Formats
独立于obj文件的调试信息.
Stabs
stabs原本是a.out中的信息,但是COFF,ELF和其他obj文件也含有有这个信息.dbxread.c:基本的stabs处理和封装,stabsread.c:干活的地方.
COFF :coff文件也含有私有的debugging信息,不太常用,扩展性不好.
Mips debug (Third Eye): ECOFF 含有的特殊调试信息, mdebugread.c
DWARF 2 : DWARF 1的下一版,但和第一版不兼容,dwarf2read.c
SOM: 和COFF类似.
Adding a New Symbol Reader to
GDB
如果使用现有的obj文件,就简单的多.否则,你需要先将新的
obj文件支持加到BFD. GDB 通过一组swaping 函数(request comment),使用具体的BFD接口,
对于特殊的target(如COFF),可能还需要一层封装,因为不同的platform可能不一样,这些接口应该在bfd/libxyz.h中进行描述.
Memory Management for Symbol
Files
一个symbol file的符号信息,存储在objfile_obstack里(request comment), unload 一个objfile的时候内存自动释放.
所以也不要在一个obj文件中引用另一个obj的符号. 和用户相关的一些数(request
comment)据和type也是存在于这个obstack里的,但是objfile
unload的时候会copy到global的内存里,所以不会丢失.
Language Support
这个东西我们不想涉及,幸好,GDBINT里说的也很少,仅仅罗列了一下步骤...
1. Create the expression parser :lang-exp.y ,一般是通过YACC parser产生所需要的parser
2. Add any evaluation routines
3.Add any evaluation routines, if necessary
4.Update some existing code
5.Add a place of call
6.Use macros to trim code
7. Edit `Makefile.in'
(这里仅仅罗列下步骤,具体请参考GDBINT, 不大关心这个.... 同时也不懂)
Host Definition
Add new Host
现在应该用autoconf来做这件事情(reques comment).老的host使用下面的配置文件.
- gdb/config/arch/xyz.mh'
- 包含host和native的配置.host configuration
现在由Autoconf处理,HOST信息包含一些定义:
XM_FILE=xm-xyz.h,还可能有CC, SYSV_DEFINE, XM_CFLAGS, XM_ADD_FILES, XM_CLIBS,
XM_CDEPS, 请参考"Makefile.in".
- gdb/config/arch/xm-xyz.h'
- 这个文件以前包含在xyz机器上运行gdb需要的一些定义和信息,现在通过Autoconf来实现.新的host和native配置不需要这个文件了.
Host Conditionals
完成GDB的配置后,需要很多的宏需要定义.这里列出了一些:
GDBINIT_FILENAME : GDB初始化文件名,一般是.gdbinit-
NO_STD_REGS : This macro is deprecated. -
SIGWINCH_HANDLER - If your host defines
SIGWINCH,
you can define this to be the name of a function to be called if SIGWINCH
is received.
SIGWINCH_HANDLER_BODY -
Define this to expand into code that will define the function named by
the expansion of
SIGWINCH_HANDLER.
ALIGN_STACK_ON_STARTUP -
Define this if your system is of a sort that will
crash in
tgetent if the stack happens not to be longword-aligned when
main is called. This is a rare situation, but is known to occur on
several different types of systems.
CRLF_SOURCE_FILES -
Define this if host files use
\r\n rather than
\n as a line terminator. This will cause source file listings to
omit \r characters when printing and it will allow \r\n line
endings of files which are "sourced" by gdb. It must be possible to
open files in binary mode using O_BINARY or, for fopen, "rb".
DEFAULT_PROMPT -
The default value of the prompt string (normally
"(gdb) ").
DEV_TTY -
The name of the generic TTY device, defaults to
"/dev/tty".
FOPEN_RB -
Define this if binary files are opened the same way as text files.
HAVE_MMAP -
In some cases, use the system call
mmap for
reading symbol tables. For some machines this allows for sharing and
quick updates.
HAVE_TERMIO -
Define this if the host system has
termio.h.
INT_MAX INT_MIN LONG_MAX UINT_MAX ULONG_MAX
- Values for host-side constants.
-
ISATTY -
Substitute for isatty, if not available.
LONGEST -
This is the longest integer type available on the host. If not
defined, it will default to
long long or long, depending on CC_HAS_LONG_LONG.
CC_HAS_LONG_LONG -
Define this if the host C compiler supports
long long.
This is set by the configure script.
PRINTF_HAS_LONG_LONG -
Define this if the host can handle printing of long long integers via
the printf format conversion specifier
ll. This is set by the configure
script.
HAVE_LONG_DOUBLE -
Define this if the host C compiler supports
long double. This is set by the
configure script.
PRINTF_HAS_LONG_DOUBLE -
Define this if the host can handle printing of long double float-point
numbers via the printf format conversion specifier
Lg. This is set
by the configure script.
SCANF_HAS_LONG_DOUBLE -
Define this if the host can handle the parsing of long double
float-point numbers via the scanf format conversion specifier
Lg.
This is set by the configure script.
LSEEK_NOT_LINEAR -
Define this if
lseek (n) does not necessarily move to byte number n in
the file. This is only used when reading source files. It is normally
faster to define CRLF_SOURCE_FILES when possible.
L_SET -
This macro is used as the argument to
lseek (or, most commonly, bfd_seek).
FIXME, should be replaced by SEEK_SET instead, which is the POSIX
equivalent.
NORETURN -
If defined, this should be one or more tokens, such as
volatile, that can
be used in both the declaration and definition of functions to
indicate that they never return. The default is already set correctly
if compiling with GCC. This will almost never need to be defined.
ATTR_NORETURN -
If defined, this should be one or more tokens, such as
__attribute__ ((noreturn)), that can
be used in the declarations of functions to indicate that they never
return. The default is already set correctly if compiling with GCC.
This will almost never need to be defined.
SEEK_CUR
-
SEEK_SET -
Define these to appropriate value for the system
lseek, if not already
defined.
STOP_SIGNAL -
This is the signal for stopping GDB. Defaults to
SIGTSTP. (Only
redefined for the Convex.)
USG -
Means that System V (prior to SVR4) include files are in use. (FIXME:
This symbol is abused in `infrun.c', `regex.c', and `utils.c' for other things, at the
moment.)
lint -
Define this to help placate
lint in some situations.
volatile -
Define this to override the defaults of
__volatile__ or /**/.
Target Architecture Definition
一种CPU的体系结构,是一个target architecture. GDB使用 struct gdbarch *来描述一种CPU的体系结构, 这个C结构及其代码,由脚本gdbarch.sh来产生.
Operating System ABI Variant
Handling
OS的ABI主要影响target defination的两个部分:sniffers and
handlers. sniffers用 于确定一种binfmt的文件属于那种BFD architecture/flavour
组合. architecture可以是通配也可以是针对特定architecture, 前者叫做genaric 后者叫specific.
一种specific的match会覆盖通配匹配.可能存在一多个OS匹配使用同一种binfmt,所以OS ABI
framework为ELF提供了一个generic sniffer:检查ELF的EI_OSABI 域(和其他的特征域).
handler 用于适配gdbarch structure的OS ABI特性.
可能一个OS只提供一种handler,为每个BFD architecture公用.这里给出一个OS ABI
的overview(具体参考GDBINI) defs.h :OS ABI变种的定义
GDB_OSABI_UNINITIALIZED : Used for struct gdbarch_info if ABI is still uninitialized.
-
GDB_OSABI_UNKNOWN: The ABI of the inferior is unknown. The default gdbarch
settings for the architecture will be used. -
GDB_OSABI_SVR4:UNIX System V Release 4. -
GDB_OSABI_LINUX
GDB_OSABI_WINCE GDB_OSABI_GO32(DJGPP)
OS ABI framework 接口函数:
const char
*gdbarch_osabi_name (enum gdb_osabi
osabi)
void gdbarch_register_osabi
(...)
void gdbarch_register_osabi_sniffer
(.....)
enum gdb_osabi gdbarch_lookup_osabi (bfd
*abfd)
void gdbarch_init_osabi (struct gdbarch
info info, struct gdbarch *gdbarch, enum gdb_osabi
osabi)
void
generic_elf_osabi_sniff_abi_tag_sections
(bfd *abfd, asection *sect, void
*obj)
Initializing a New Architecture
每个gdbarch对应一个BFD architecture,并有一个常量bfd_arch_xxx.
通过函数register_gdbarch_init 注册gdbarch ,通常在
_initialize_filename 中调用注册函数,这样就加入了GDB启动流程. (细节请参考GDBINT)
Registers and Memory
GDB 采用的target machine模型是十分简单的:GDB
假定一种机器包含一组寄存器和一块内存,每个寄存器有一定的大小.GDB把寄存器的一切封装到像 gdbarch_register_name 这样的一系列函数中,继而做到正确处理.GDB
支持各种endian的机器:big-endian, little-endian, bi-endian(request commnet).
Pointers Are Not Always Addresses
有些特殊的平台,同一个word,其用于code pointer和datapointe的时候有不同的解释,比如D10V,同样是0xC020,当用于数据地址的时候代表地址0xC020,但是用于代码地址的时候,需要转换一下,代表0x30080(详
见D10V或者GDBINT).
所以在GDB中,对于address和pointer是区分对待的.address代表字节地址,而pointer指向特定的数据类型:data
or code or other...., pointer需要转换以下才是address,大部分平台是相等的值,部分平台需要移位等操作.
但是大部分平台上,这两者是等价的,以下函数用于转换pointer和address: (详见GDBINT)
CORE_ADDR extract_typed_address (void *buf,
struct type *type)
CORE_ADDR store_typed_address (void *buf, struct
type *type, CORE_ADDR addr)
CORE_ADDR value_as_address (struct value
*val)
CORE_ADDR value_from_pointer (struct type *type,
CORE_ADDR addr)
CORE_ADDR gdbarch_pointer_to_address (struct gdbarch
*current_gdbarch, struct type *type, char
*buf)
void gdbarch_address_to_pointer (struct gdbarch
*current_gdbarch, struct type *type, char
*buf, CORE_ADDR addr)
Address Classes
当不同种类的address可以而从调试信息中(如DWARF2)获取时, 应该定义以下宏来支持GDB认知这些区别,或者给GDB
user提供类型信息.
int gdbarch_address_class_type_flags (struct gdbarch
*current_gdbarch, int byte_size, int
dwarf2_addr_class)
char *gdbarch_address_class_type_flags_to_name (struct gdbarch
*current_gdbarch, int type_flags)
int gdbarch_address_class_name_to_type_flags (struct gdbarch
*current_gdbarch, int name, int
*var{type_flags_ptr})
祥见GDBINT.
Raw and Virtual Register Representations
注:这里描述的内容已经过时,请参考下一节.
一些体系结构在寄存器和内存中对一个值的表达方式是不同的.用GDB的术语来定义,在寄存器中的表达方式叫raw
representation,在内存中的表达方式叫做virtual representation.GDB用struct value
objects来表示这种差异.
在几乎所有的体系上,数据类型的virtual和raw representations 是一致的.但是有例外,如:
x86 提示支持一种80-bit long double
type,但是存储到内存时,占用12个byte:浮点数占用头是个byte,后两个byte没有用(对齐要求),因此,x86 80-bit
floating-point type 就是raw representation,twelve-byte loosely-packed
arrangement 是virtual representation.
另外,一些64-bit MIPS,使用64-bit的寄存器当作32-bit
registers使用,高位是垃圾数据.所以,64-bit form, 带有垃圾数据的这种表达形式是raw representation,
32-bit 形式是virtual representation.
GDB's register file, registers, 采用raw format, GDB remote protocol
transmits register values也是raw format.如要如下的函数支持raw和virtual模式的转换.
int REGISTER_CONVERTIBLE (int reg)
/*是否需要转换*/
int DEPRECATED_REGISTER_RAW_SIZE (int reg)
/*返回raw格式占用的字节数*/
int DEPRECATED_REGISTER_VIRTUAL_SIZE (int
reg)/*vitural 格式占用的字节数*/
struct type *DEPRECATED_REGISTER_VIRTUAL_TYPE
(int reg) /*返回vitual representation*/
void REGISTER_CONVERT_TO_VIRTUAL (int reg, struct type
*type, char *from, char *to)
void REGISTER_CONVERT_TO_RAW (struct type *type, int
reg, char *from, char *to)
Using Different Register and Memory Data Representations
Maintainer's note: GDB操作寄存器的方式正在变革中,详见
A.R. Index and
Bug Tracking Database
2002.
这里解决的问题和上一节一样:x86 80-bit 浮点寄存器,还有Alpha 可以把32 bit integer values
存到floating-point registers.
这种问题也可以定义如下的宏来解决:
int gdbarch_convert_register_p (struct
gdbarch *gdbarch, int reg) /*是否必要转换*/
void gdbarch_register_to_value (struct gdbarch *gdbarch,
int reg, struct type *type, char
*from, char *to)
/*from raw to value*/
void gdbarch_value_to_register (struct gdbarch
*gdbarch, struct type *type, int reg,
char *from, char *to)/*转换到raw format*/
void REGISTER_CONVERT_TO_TYPE (int
regnum, struct type *type, char *buf)
/*refer to `mips-tdep.c',事情很复杂(request comments)
Target Conditionals
这里讨论的宏和函数用于定义新的target.
Register and Bit structure:
BITS_BIG_ENDIAN :如果target的bis endin和byte endianness不同,则定义此值.
TARGET_CHAR_BIT /* defaults to 8.*/
int gdbarch_char_signed (gdbarch) /*non-zero, 如果char通常是带符号的整数的话*//*unsigned on IBM S/390, RS6000, and PowerPC*/
int gdbarch_double_bit (gdbarch) /*默认是 8 * TARGET_CHAR_BIT.*/
int gdbarch_float_bit (gdbarch) /* defaults to 4 * TARGET_CHAR_BIT*/
int gdbarch_int_bit (gdbarch) /*默认是 4 * TARGET_CHAR_BIT.*/
int gdbarch_long_bit (gdbarch)/*defaults to 4 * TARGET_CHAR_BIT.*/
int gdbarch_long_double_bit (gdbarch)/*defaults to 2 * gdbarch_double_bit (gdbarch).*/
int gdbarch_long_long_bit (gdbarch)/*defaults to 2 * gdbarch_long_bit (gdbarch).*/
int gdbarch_ptr_bit (gdbarch)/* defaults to gdbarch_int_bit (gdbarch).*/
int gdbarch_short_bit (gdbarch)/* defaults to 2 * TARGET_CHAR_BIT.*/
int gdbarch_cannot_store_register (gdbarch, regnum)/*比如PC,状态寄存器等*/
int gdbarch_convert_register_p (gdbarch, regnum, struct type *type)/*need raw <-> vitral ?*/
void gdbarch_value_to_register (gdbarch, frame, type, buf) /* convert value to raw (register)*/
int gdbarch_sp_regnum (gdbarch) /*返回堆栈指针寄存器的编号*/
register_reggroup_p (gdbarch, regnum, reggroup)/*float_reggroup,vector_reggroup...restore_reggroup..*/
DEPRECATED_REGISTER_VIRTUAL_SIZE (reg)/*raw and virtal for reg and memory*/
DEPRECATED_REGISTER_VIRTUAL_TYPE (reg)
struct type *register_type (gdbarch, reg)/*refer to raw virtual register representations*/
REGISTER_CONVERT_TO_VIRTUAL(reg, type, from, to)
REGISTER_CONVERT_TO_RAW(type, reg, from, to)
const struct regset *regset_from_core_section (struct gdbarch * gdbarch, const char * sect_name, size_t sect_size) /*为core file的section返回一个合适的regset*/
void gdbarch_register_to_value(gdbarch, frame, regnum, type, fur)/*Register
and Memory Representations.*/
const char *gdbarch_register_name (gdbarch, regnr) /*返回寄存器名称*/
int gdbarch_stab_reg_to_regnum (gdbarch, stab_regnr)/*optinal,stab register stab_regnr 到GDB regnum转换*/
void gdbarch_store_return_value (gdbarch, type, regcache, valbuf)/*been deprecated by gdbarch_return_value*/
gdbarch_ps_regnum (gdbarch /* 返回处理器状态寄存器编号用于解析 "$ps"*/
int gdbarch_sdb_reg_to_regnum (gdbarch, sdb_regnr)/*sdb_regnr到GDB regnum的转换,optional*/
Stack Frame:
SOFTWARE_SINGLE_STEP_P() /*如果无hardware的单步机制*/
SOFTWARE_SINGLE_STEP(signal, insert_breakpoints_p)/*refer to `sparc-tdep.c' and `rs6000-tdep.c'*/
DEPRECATED_FRAME_SAVED_PC(frame) /* 返回frame中的PC地址*//*deprecated.
See
gdbarch_unwind_pc.*/
CORE_ADDR gdbarch_unwind_pc (next_frame)/*Return the retrun address*/
CORE_ADDR gdbarch_unwind_sp (gdbarch, next_frame) /*
Return the frame's inner most stack address*/
CORE_ADDR frame_align (gdbarch, address)
int gdbarch_frame_red_zone_size (gdbarch) /*ABI reserverd stack address,refer
AMD64 (nee x86-64) ABI */
DEPRECATED_FRAME_CHAIN(frame) /* retern calling frame*/
DEPRECATED_FRAME_CHAIN_VALID(chain, thisframe)/* 0:最外层frame,此时PC一般位于ctr0.o*/
DEPRECATED_FRAME_INIT_SAVED_REGS(frame)/* See `frame.h'*/
int gdbarch_frame_num_args (gdbarch, frame)/*返回frame的参数个数(request comments)*/
void gdbarch_extract_return_value (gdbarch, type, regbuf, valbuf) /*deprecated by gdbarch_return_value
*/
DEPRECATED_FP_REGNUM /* need to be defined if DEPRECATED_TARGET_READ_FP is not defined.*/
DEPRECATED_FRAMELESS_FUNCTION_INVOCATION(fi)/*如果函数调用fi无stack frame,返回0*/
FUNCTION_EPILOGUE_SIZE /*比如COFF targets,无epilogue信息*/
DEPRECATED_FUNCTION_START_OFFSET /*一般是0,从函数地址到其第一条指令的字节长度,如VAX*/
int gdbarch_inner_than (gdbarch, lhs, rhs) /* is lhs inner than rhs?*/
gdbarch_in_function_epilogue_p (gdbarch, addr)/* addr is in the epilogue of a function?*/
int gdbarch_in_solib_return_trampoline (gdbarch, pc, name)/*程序stop在一个共享库的trampoline?*/
IN_SOLIB_DYNSYM_RESOLVE_CODE (pc) /*the program stop在一个dynamic linker内?*/
SKIP_SOLIB_RESOLVER (pc) /*是否需要跳过dynamic linker的symbol resolution
函数?*/
gdbarch_get_longjmp_target /*longjmp要跳到的PC地址*/
TARGET_READ_SP /*gdbarch_unwind_sp
replace this*/
TARGET_READ_FP /*gdbarch_unwind_sp
replace this*/
void gdbarch_virtual_frame_pointer (gdbarch, pc, frame_regnum, frame_offset) /*返回代表pc位置的virtual frame pointer(register, offset)*/
CORE_ADDR gdbarch_read_pc (gdbarch, regcache) /*一般不用定义*/
gdbarch_write_pc (gdbarch, regcache, val)
DEPRECATED_USE_STRUCT_CONVENTION (gcc_p, type) /* 如过type作为函数返回值是使用struct,返回非零值(需要在堆栈分配空间*//*been deprecated by gdbarch_return_value (see
gdbarch_return_value).
*/
CORE_ADDR gdbarch_addr_bits_remove (gdbarch, addr) /*移去PC中不是地址的那些部分,比如privilege code*/
int gdbarch_call_dummy_location (gdbarch) /*refer to inferior.h.
been replaced by gdbarch_push_dummy_code */
int gdbarch_cannot_fetch_register
(gdbarch,
regum)/*返回nonzore,如果regno不能从被调试程序获得*/
int gdbarch_stabs_argument_has_addr (gdbarch, type) /*如果函数的参数类型'type'是'引用'性质,返回非零值*/
CORE_ADDR gdbarch_skip_prologue (gdbarch, ip)/*返回函数真正代码(跳过prelogue)的地址*/
CORE_ADDR gdbarch_skip_trampoline_code (gdbarch, frame, pc)/*跳过caller和be called函数之间的trampoline code */
enum return_value_convention gdbarch_return_value (struct gdbarch *gdbarch, struct type *valtype, struct regcache *regcache, void *readbuf, const void *writebuf) /*返回'函数返回值'转换类型:RETURN_VALUE_REGISTER_CONVENTION,RETURN_VALUE_STRUCT_CONVENTION */
SAVE_DUMMY_FRAME_TOS (sp) /* Used in
`call_function_by_hand',(comments)refer to
gdbarch_unwind_dummy_id*/
CORE_ADDR gdbarch_push_dummy_call (gdbarch, function, regcache, bp_addr, nargs, args, sp, struct_return, struct_addr) /*在堆栈上建立调用被调试程序函数的堆栈,返回调整后的堆栈顶指针(pointer)*/
CORE_ADDR gdbarch_push_dummy_code (gdbarch, sp, funaddr, using_gcc, args, nargs, value_type, real_pc, bp_addr, regcache) /*建立一个被调用函数返回后执行的代码序列 (request comments)*/
DEPRECATED_REG_STRUCT_HAS_ADDR (gcc_p, type) /*判断type是否采用指针传递方式*/
/*be replaced by gdbarch_stabs_argument_has_addr*/
Address pointer:
int address_class_name_to_type_flags (gdbarch, name, type_flags_ptr) /*如合法,设置class flag*/
int address_class_name_to_type_flags_p (gdbarch) /* address_class_name_to_type_flags是否被定义*/
int gdbarch_address_class_type_flags (gdbarch, byte_size, dwarf2_addr_class)/*从指针的bytesize和调试信息,给出address class type*/int gdbarch_address_class_type_flags_p (gdbarch)/* gdbarch_address_class_type_flags_p 是否被定义*/const char *gdbarch_address_class_type_flags_to_name (gdbarch, type_flags)
/*address class to name*/
int gdbarch_address_class_type_flags_to_name_p (gdbarch) /*gdbarch_address_class_type_flags_to_name 是否定义*/void gdbarch_address_to_pointer (gdbarch, type, buf, addr)
/*将类型为type的 addr转换为指针存入buf*/CORE_ADDR gdbarch_integer_to_address (gdbarch, type, buf) /*如果需要从int到address的转换,定义此函数*/CORE_ADDR gdbarch_pointer_to_address (gdbarch, type, buf)
DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS(regbuf)/*When defined,extract raw regbuf to CORE_ADDR */
DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P() /* Predicate for DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS.*/ -
Compiler and BFD:
int gdbarch_believe_pcc_promotion (gdbarch)/*编译其是否把char 或者short提升为int?*/
int gdbarch_dwarf2_reg_to_regnum (gdbarch, dwarf2_regnr)/*for dwarf2*/
int gdbarch_ecoff_reg_to_regnum (gdbarch, ecoff_regnr)
int gdbarch_dwarf_reg_to_regnum (gdbarch, dwarf_regnr)/*dwarf_regnr 到GDB regnum转换,should optional*/
GCC_COMPILED_FLAG_SYMBOL/*(Currently only defined for the Delta 68.)*/
GCC2_COMPILED_FLAG_SYMBOL/*(Currently only defined for the Delta 68.)*/
SOFUN_ADDRESS_MAYBE_MISSING /*表示stabs-format debugging
information中N_FUN(函数起始和结束地址)和N_SO(compilation unit 的起始和结束地址)是0,
需要以其他方式确定*/
PROCESS_LINENUMBER_HOOK /*XCOFF reading hook*/
VARIABLES_INSIDE_BLOCK (desc, gcc_p) /*For dbx-style debugging information, if the
compiler puts variable declarations inside LBRAC/RBRAC blocks, this
should be defined to be nonzero. refer to GDBINT*/
BreakPoint wathpoint
BREAKPOINT :定义breakpoint使用的指令,不能长于最短指令.如果采用trap则不必定义.如果才用非法指令或者其他值则必须定义TARGET_HAS_HARDWARE_WATCHPOINTS
BIG_BREAKPOINT LITTLE_BREAKPOINT :类似BREAKPOINT, 但是用于 bi-endian targets.
const gdb_byte *gdbarch_breakpoint_from_pc (gdbarch, pcptr, lenptr) /*将一个breakpointPC位置,返回一个breakpointe指令的长度并调整pc位置到插入点,如果是采用trap指令,则不需要这个函数*/
int gdbarch_memory_insert_breakpoint (gdbarch, bp_tgt)
gdbarch_memory_remove_breakpoint (gdbarch, bp_tgt) /*有默认函数,除非有特殊处理,否则无需这两个函数.*/
CORE_ADDR gdbarch_adjust_breakpoint_address (gdbarch, bpaddr) /*一般target不需要,可以参考frv-tdep.c*/
I386_USE_GENERIC_WATCHPOINTS /*for i386, self explanation*/
DISABLE_UNSETTABLE_BREAK (addr)/*如果addr位于共享库,返回1,代表不可以设置break*/
CORE_ADDR gdbarch_decr_pc_after_break (gdbarch)
/*遇到break后需要对PC进行的调整,一般要回退BREAKPOINT大小
*/
void gdbarch_skip_permanent_breakpoint (gdbarch, regcache) /*如果被调试程序有硬编码的breakpoint,此函数调整pc跳过这种breakpoint*/
User Interface
void gdbarch_print_float_info (gdbarch, file, frame, args)/*定义此函数后,info float命令可以打印浮点单元信息*/
void gdbarch_print_registers_info (gdbarch, frame, regnum, all)/*格式化输出,optinal*/
int gdbarch_print_vector_info (gdbarch, file, frame, args)/*info vector的格式化输出,optional*/
int gdbarch_print_insn (gdbarch, vma, info) /*打印汇编指令*//*默认使用deprecated_tm_print_insn,refer toOpcodes*/ frame_id gdbarch_unwind_dummy_id (gdbarch, frame)/*返回被调试程序函数的dummy frameSee
SAVE_DUMMY_FRAME_TOS.*/
Motorola M68K:
BPT_VECTOR : Define this to be the 4-bit location of the
breakpoint trap vector. If not defined, it will default to 0xf.
REMOTE_BPT_VECTOR: Defaults to 1.
const char *gdbarch_name_of_malloc (gdbarch) : A string containing the
name of the function to call in order to allocate some memory in the
inferior. The default value is "malloc".
Misc: DEPRECATED_IBM6000_TARGET /*should be eliminated (FIXME)*/
SYMBOL_RELOADING_DEFAULT /* (Never defined in current sources.)*/
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'. /*为cpu相同的target所共享*/
- 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的接口如下:
-
%l1 和 %l2 分别包含pc 和 npc;
-
traps 以禁止;
-
已经在正确的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->v)) { we have some contents } VEC_safe_push(tree, s->v, decl); // append some decl onto the end for (ix = 0; VEC_iterate(tree, s->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
CommentsC Usage
Function Prototypes
Internal Error RecoveryFile NamesInclude FilesClean 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') :
- 配置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
|