GDB 使用指南

GDB

Wikipedia

GNU调试器(英语:GNU Debugger,缩写:GDB),是GNU软件系统中的标准调试器,此外GDB也是个具有移携性的调试器,经过移携需求的调修与重新编译,如今许多的类UNIX操作系统上都可以使用GDB,而现有GDB所能支持调试的编程语言有C、C++、Pascal以及FORTRAN。

相关链接: GDB: The GNU Project Debugger

本文参考资料

GDB 的基本使用

接下来只涉及一小部分常用的命令,更多的常用命令查阅上面提到的参考资料

💡 样例程序
这里以 CSAPP 的 BombLab 的 phase_1 阶段为例:

  • 实验简介:只有在输入正确的字符串后才可避免💣爆炸,目标是正确拆除所有💣
  • 实验说明书
  • 下载链接

实验环境

  • Ubuntu 20.04 LTS
  • GDB Version: GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
  • 不安装 gef、peda、pwndbg 等

启动程序

使用 GDB 调试目标程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
❯ gdb bomb
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from bomb...
(gdb)

此时目标程序尚未运行,不过可以使用 info functions 查看函数符号表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(gdb) info functions
All defined functions:

File bomb.c:
36: int main(int, char **);

Non-debugging symbols:
0x0000000000400ac0 _init
0x0000000000400ae0 getenv@plt
0x0000000000400af0 __errno_location@plt
0x0000000000400b00 strcpy@plt
...
0x0000000000400ee0 phase_1
0x0000000000400efc phase_2
0x0000000000400f43 phase_3
0x0000000000400fce func4
0x000000000040100c phase_4
0x0000000000401062 phase_5
0x00000000004010f4 phase_6
0x0000000000401204 fun7
...

使用 disassemble 命令(简写 disass)反编译指定的函数:

1
2
3
4
5
6
7
8
9
10
11
(gdb) disass phase_1
Dump of assembler code for function phase_1:
0x0000000000400ee0 <+0>: sub $0x8,%rsp
0x0000000000400ee4 <+4>: mov $0x402400,%esi
0x0000000000400ee9 <+9>: callq 0x401338 <strings_not_equal>
0x0000000000400eee <+14>: test %eax,%eax
0x0000000000400ef0 <+16>: je 0x400ef7 <phase_1+23>
0x0000000000400ef2 <+18>: callq 0x40143a <explode_bomb>
0x0000000000400ef7 <+23>: add $0x8,%rsp
0x0000000000400efb <+27>: retq
End of assembler dump.

此时的汇编语法是 AT&T 风格的,可以使用 set disassembly-flavor intel 切换至 intel 风格:

1
2
3
4
5
6
7
8
9
10
11
12
(gdb) set disassembly-flavor intel
(gdb) disass phase_1
Dump of assembler code for function phase_1:
0x0000000000400ee0 <+0>: sub rsp,0x8
0x0000000000400ee4 <+4>: mov esi,0x402400
0x0000000000400ee9 <+9>: call 0x401338 <strings_not_equal>
0x0000000000400eee <+14>: test eax,eax
0x0000000000400ef0 <+16>: je 0x400ef7 <phase_1+23>
0x0000000000400ef2 <+18>: call 0x40143a <explode_bomb>
0x0000000000400ef7 <+23>: add rsp,0x8
0x0000000000400efb <+27>: ret
End of assembler dump.

📌 AT&T 与 intel 语法有何区别?

AT&T 和 Intel 汇编语法的主要区别

后续内容默认使用 intel 汇编语法

使用 break 命令添加断点:

1
2
3
(gdb) b phase_1
Breakpoint 1 at 0x400ee0
(gdb)

break 命令

  • 可以直接在指定地址处下断点: break *0x400ee0
  • 也可以在已知的函数符号后加一定的偏移处下断点: break *main+10

断点相关

  • 查看已经存在的断点信息: info breakpoints
  • 删除指定断点:del 1

使用 runstart 命令启动程序:

1
2
3
4
5
6
7
8
(gdb) run
Starting program: /home/ubuntu/Datas/study/bomb/bomb
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
ABCD // 这里是输入的内容

Breakpoint 1, 0x0000000000400ee0 in phase_1 ()
(gdb)

📌 runstart 命令的区别是什么?

  • run 会一直执行程序,直到执行到设置的断点处停下;
  • start 会执行程序到 main() 函数起始处停下,等同于先执行了 break main 后执行 run

分析 phase_1

执行 disass,会反汇编得到当前断点处所在的函数(phase_1)的汇编代码:

1
2
3
4
5
6
7
8
9
10
11
(gdb) disass
Dump of assembler code for function phase_1:
=> 0x0000000000400ee0 <+0>: sub rsp,0x8
0x0000000000400ee4 <+4>: mov esi,0x402400 // 这里可以看到第二个参数传递了一个全局变量地址
0x0000000000400ee9 <+9>: call 0x401338 <strings_not_equal>
0x0000000000400eee <+14>: test eax,eax
0x0000000000400ef0 <+16>: je 0x400ef7 <phase_1+23>
0x0000000000400ef2 <+18>: call 0x40143a <explode_bomb>
0x0000000000400ef7 <+23>: add rsp,0x8
0x0000000000400efb <+27>: ret
End of assembler dump.

第一个参数则是会通过 rdi 寄存器进行传参,接下来查看 rdi 的值:

  • 使用 info reg 可以查看当前的所有寄存器信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
(gdb) info reg
rax 0x603780 6305664
rbx 0x402210 4203024
rcx 0x4 4
rdx 0x1 1
rsi 0x603780 6305664
rdi 0x603780 6305664
rbp 0x0 0x0
rsp 0x7fffffffe348 0x7fffffffe348
r8 0x603780 6305664
r9 0x7c 124
r10 0xfffffffffffffe34 -460
r11 0x7ffff7e004a0 140737352041632
r12 0x400c90 4197520
r13 0x7fffffffe440 140737488348224
r14 0x0 0
r15 0x0 0
rip 0x400ee0 0x400ee0 <phase_1>
eflags 0x206 [ PF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb)
  • 或者使用 print 来输出当前的 rdi 寄存器值:
1
2
3
(gdb) print /x $rdi   // 以十六进制形式打印 rdi 寄存器的值
$1 = 0x603780
(gdb)

使用 x 命令打印出其中的字符串内容:

1
2
3
4
5
(gdb) x/s 0x603780    // 打印出指定地址存储的字符串
0x603780 <input_strings>: "ABCD"
// 一并打印下第二个参数指向的数据内容:
(gdb) x/s 0x402400
0x402400: "Border relations with Canada have never been better."

print 与 x 命令的更多帮助信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(gdb) help x
Examine memory: x/FMT ADDRESS.
ADDRESS is an expression for the memory address to examine.
FMT is a repeat count followed by a format letter and a size letter.
Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),
t(binary), f(float), a(address), i(instruction), c(char), s(string)
and z(hex, zero padded on the left).
Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).
The specified number of objects of the specified size are printed
according to the format. If a negative number is specified, memory is
examined backward from the address.

Defaults for format and size letters are those previously used.
Default count is 1. Default address is following last thing printed
with this command or "print".
1
2
3
4
5
x/nfu addr

n: 输出单元的个数
f: 输出单元的格式 o/x/d/u/t/f/a/i/c/s/z
u: 每个输出单元的长度 b/h/w/g

打印栈上的数据
我们也可以使用 x 命令来打印栈的数据:

1
2
3
4
5
6
(gdb) x/10gx $rsp
0x7fffffffe348: 0x0000000000400e3f 0x0000000000402210
0x7fffffffe358: 0x00007ffff7df0083 0x0000000000000000
0x7fffffffe368: 0x00007fffffffe448 0x0000000100000000
0x7fffffffe378: 0x0000000000400da0 0x0000000000402210
0x7fffffffe388: 0x4f838435c81d5e78 0x0000000000400c90

比较明显的可以得知,接下来程序会对比这两个字符串是否一致,一致时💣可以被解除

重新执行 run,输入刚刚发现的目标字符串

为了方便调试,可以执行 layout regs 来切换到下面的布局:

Pasted image 20220901172524

tui 相关
GDB手册 - GDB Text User Interface

  • 关闭上面的界面,回归正常模式: tui disable

进行单步执行:stepi / nexti

Pasted image 20220901173832

函数返回值存储在 rax 中,值为 0 表示两个字符串相等,然后会跳过 explode_bomb 函数,继续执行程序

📌 stepinexti 的区别是什么?

  • stepi(si):执行一条指令,遇到函数调用时进入函数内部
  • nexti(ni):类似于stepi,但是遇到函数调用时不会进入,直接跳过

继续执行程序 continue,可以发现💣解除了一个:

1
2
3
(gdb) c
Continuing.
Phase 1 defused. How about the next one?

GDB + Pwndbg 常用命令

整理一下 gdb + pwndbg 的一些常用命令

运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ gdb program
# 运行程序,简写r
(gdb) run
# 带参数运行程序(method 1)
(gdb) run arg1 arg2
# 带参数运行程序(method 2)
(gdb) set args arg1 arg2
(gdb) run
# 指定标准输入
(gdb) run <file
(gdb) run < <(python3 -c 'print(b"A"*10)')
(gdb) run <<<$(python3 -c 'print(b"A"*10)')
# 链接到正在运行的进程,并进行调试
(gdb) attach {process-id}
# 断开链接
(gdb) detach
# 查看历史命令
(gdb) show commands
# 执行上一条命令
(gdb) <enter>
# 从文件中加载gdb命令
(gdb) source {filepath}
# 退出gdb (简写q)
(gdb) quit
# 帮助
(gdb) help
1
2
# 查看 pwndbg 命令帮助
pwndbg> pwndbg

断点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 添加断点(指定函数名)
(gdb) break main
# 添加断点(指定内存地址)
(gdb) break *0x00400123
# 列出所有断点信息(简写info b)
(gdb) info breakpoints
# 删除编号为1的断点
(gdb) delete 1
# 删除所有断点(简写del)
(gdb) delete
# 删除内存地址的断点
(gdb) clear *0x00400123
# 禁用指定编号断点
(gdb) disable 2
# 启用指定编号断点
(gdb) enable 2
# 条件断点
(gdb) condition {id} {expr}
2 i == 10 # 只有在 i==10 成立时2号断点生效
# 继续执行(简写c)
(gdb) continue
# 单步进入(遇到函数会进入)
(gdb) stepi
# 单步跳过(遇到函数不会进入)
(gdb) nexti
# 结束当前函数
(gdb) finish

源代码及反汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 查看指定函数附近的代码
(gdb) list main
# 查看指定地址的代码
(gdb) list *0x00400800
# 添加源代码搜索路径
(gdb) dir {dirpath}
# 复原源代码搜索路径
(gdb) dir
# 查看源代码搜索路径
(gdb) show directories
# 打印当前执行函数的汇编代码
(gdb) disas
# 打印指定函数的反汇编代码
(gdb) disas main
# 对指定地址进行反汇编
(gdb) disas {address}
# 打印程序中的函数
(gdb) info functions
# 更改显示风格
(gdb) set disassembly-flavor att
(gdb) set disassembly-flavor intel
1
2
3
4
# 设置默认只显示源代码段
pwndbg> set context-sections code
# 显示源代码段
pwndbg> ctx code

1
2
3
4
5
6
7
8
# 打印backtrace(简写bt)
(gdb) backtrace
# 打印当前运行的栈帧
(gdb) frame
# 切换到指定编号的栈帧
(gdb) frame {id}
# 显示当前函数参数
(gdb) info args
1
2
# 查看栈数据
pwndbg> stack

数据查看

1
2
3
4
5
6
7
8
9
10
11
12
# 打印出表达式结果
(gdb) print {expression}
# 十六进制输出结果
(gdb) print /x {expr}
/x 十六进制
/o 八进制
/d 十进制
/t 二进制
# 打印历史记录条目
(gdb) print $1
# 打印指定寄存器数据
(gdb) print /x $rax
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 从指定地址处读取数据
(gdb) x/[数量][长度单位][显示格式] where
长度单位:
/b 以1字节为单位读取数据
/w 以4字节为单位读取数据
/g 以8字节为单位读取数据

/i 尝试解析成汇编

例如:
(gdb) x/8gx $rsp+8
0x7fffffffe478: 0x00007fffffffe6ef 0x0000000000000000
0x7fffffffe488: 0x00007fffffffe70e 0x00007fffffffe729
0x7fffffffe498: 0x00007fffffffe739 0x00007fffffffe74c
0x7fffffffe4a8: 0x00007fffffffe758 0x00007fffffffe767
(gdb) x/4wd $rsp+8
0x7fffffffe478: -6417 32767 0 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# pwndbg 中加入的 db(dump byte) dw(dump word) dq(dump qword)
# db address [count] , 命令后可以指定打印的数量, 不指定则使用默认值
pwndbg> db $rsp
00007fffffffe470 01 00 00 00 00 00 00 00 ef e6 ff ff ff 7f 00 00
00007fffffffe480 00 00 00 00 00 00 00 00 0e e7 ff ff ff 7f 00 00
00007fffffffe490 29 e7 ff ff ff 7f 00 00 39 e7 ff ff ff 7f 00 00
00007fffffffe4a0 4c e7 ff ff ff 7f 00 00 58 e7 ff ff ff 7f 00 00
pwndbg> dw $rsp
00007fffffffe470 0001 0000 0000 0000 e6ef ffff 7fff 0000
00007fffffffe480 0000 0000 0000 0000 e70e ffff 7fff 0000
00007fffffffe490 e729 ffff 7fff 0000 e739 ffff 7fff 0000
00007fffffffe4a0 e74c ffff 7fff 0000 e758 ffff 7fff 0000
pwndbg> dq $rsp
00007fffffffe470 0000000000000001 00007fffffffe6ef
00007fffffffe480 0000000000000000 00007fffffffe70e
00007fffffffe490 00007fffffffe729 00007fffffffe739
00007fffffffe4a0 00007fffffffe74c 00007fffffffe758
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 查看寄存器数据
(gdb) info registers
# 打印本地局部变量
(gdb) info locals
# 打印全局变量名称
(gdb) info variables
# 查看类型定义
(gdb) ptype {typename}

(gdb) ptype main_arena
type = struct malloc_state {
__libc_lock_t mutex;
int flags;
int have_fastchunks;
mfastbinptr fastbinsY[10];
mchunkptr top;
mchunkptr last_remainder;
mchunkptr bins[254];
unsigned int binmap[4];
struct malloc_state *next;
struct malloc_state *next_free;
size_t attached_threads;
size_t system_mem;
size_t max_system_mem;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# pwndbg 中加入 dt (Dump out information on a type (e.g. ucontext_t).)
# 打印指定类型的信息(可选指定address)
dt typename [address]

pwndbg> dt FILE
FILE
+0x0000 _flags : int
+0x0008 _IO_read_ptr : char *
+0x0010 _IO_read_end : char *
+0x0018 _IO_read_base : char *
+0x0020 _IO_write_base : char *
+0x0028 _IO_write_ptr : char *
+0x0030 _IO_write_end : char *
+0x0038 _IO_buf_base : char *
+0x0040 _IO_buf_end : char *
+0x0048 _IO_save_base : char *
+0x0050 _IO_backup_base : char *
+0x0058 _IO_save_end : char *
+0x0060 _markers : struct _IO_marker *
+0x0068 _chain : struct _IO_FILE *
+0x0070 _fileno : int
+0x0074 _flags2 : int
+0x0078 _old_offset : __off_t
+0x0080 _cur_column : short unsigned int
+0x0082 _vtable_offset : signed char
+0x0083 _shortbuf : char [1]
+0x0088 _lock : _IO_lock_t *
+0x0090 _offset : __off64_t
+0x0098 _codecvt : struct _IO_codecvt *
+0x00a0 _wide_data : struct _IO_wide_data *
+0x00a8 _freeres_list : struct _IO_FILE *
+0x00b0 _freeres_buf : void *
+0x00b8 __pad5 : size_t
+0x00c0 _mode : int
+0x00c4 _unused2 : char [20]

# 显示malloc_state结构体信息(有各个字段的偏移
pwndbg> dt "struct malloc_state"
struct malloc_state
+0x0000 mutex : __libc_lock_t
+0x0004 flags : int
+0x0008 have_fastchunks : int
+0x0010 fastbinsY : mfastbinptr [10]
+0x0060 top : mchunkptr
+0x0068 last_remainder : mchunkptr
+0x0070 bins : mchunkptr [254]
+0x0860 binmap : unsigned int [4]
+0x0870 next : struct malloc_state *
+0x0878 next_free : struct malloc_state *
+0x0880 attached_threads : size_t
+0x0888 system_mem : size_t
+0x0890 max_system_mem : size_t
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# pwndbg 中加入 xinfo(Shows offsets of the specified address to useful other locations)
# 显示指定地址到有用位置的偏移
pwndbg> xinfo [address]

pwndbg> xinfo
Extended information for virtual address 0x5555555548d0:

Containing mapping:
0x555555554000 0x55555555a000 r-xp 6000 0 /home/ubuntu/Documents/pwn/pwn

Offset information:
Mapped Area 0x5555555548d0 = 0x555555554000 + 0x8d0
File (Base) 0x5555555548d0 = 0x555555554000 + 0x8d0
File (Segment) 0x5555555548d0 = 0x555555554000 + 0x8d0
File (Disk) 0x5555555548d0 = /home/ubuntu/Documents/pwn/pwn + 0x8d0

Containing ELF sections:
.text 0x5555555548d0 = 0x5555555548d0 + 0x0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# vis_heap_chunks(Visualize chunks on a heap, default to the current arena's active heap.)
# 可视化显示当前堆分配情况
pwndbg> vis_heap_chunks

pwndbg> heap
pwndbg> bins
pwndbg> fastbins
pwndbg> smallbins
pwndbg> largebins
pwndbg> tcache
pwndbg> tcachebins

# malloc_chunk(Print a chunk.)
# 打印出指定地址的 malloc_chunk
pwndbg> malloc_chunk [addr]

进程调试

1
2
# 设置当进程调用fork时是否进入子进程
(gdb) set follow-fork-mode parent/child

其他

GDB 调试 16位程序

set arch i8086 命令并不能生效,下面的解决办法来自 这里

1
2
3
4
echo '<?xml version="1.0"?><!DOCTYPE target SYSTEM "gdb-target.dtd"><target><architecture>i8086</architecture><xi:include href="i386-32bit.xml"/></target>' > target.xml
wget https://raw.githubusercontent.com/qemu/qemu/master/gdb-xml/i386-32bit.xml

(gdb) set tdesc filename ./target.xml
target.xml

1
2
3
4
5
<?xml version="1.0"?><!DOCTYPE target SYSTEM "gdb-target.dtd">
<target>
<architecture>i8086</architecture>
<xi:include href="i386-32bit.xml"/>
</target>
i386-32bit.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
<?xml version="1.0"?>
<!-- Copyright (C) 2010-2017 Free Software Foundation, Inc.

Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. -->

<!-- I386 with SSE -->

<!DOCTYPE target SYSTEM "gdb-target.dtd">
<feature name="org.gnu.gdb.i386.core">
<flags id="i386_eflags" size="4">
<field name="" start="22" end="31"/>
<field name="ID" start="21" end="21"/>
<field name="VIP" start="20" end="20"/>
<field name="VIF" start="19" end="19"/>
<field name="AC" start="18" end="18"/>
<field name="VM" start="17" end="17"/>
<field name="RF" start="16" end="16"/>
<field name="" start="15" end="15"/>
<field name="NT" start="14" end="14"/>
<field name="IOPL" start="12" end="13"/>
<field name="OF" start="11" end="11"/>
<field name="DF" start="10" end="10"/>
<field name="IF" start="9" end="9"/>
<field name="TF" start="8" end="8"/>
<field name="SF" start="7" end="7"/>
<field name="ZF" start="6" end="6"/>
<field name="" start="5" end="5"/>
<field name="AF" start="4" end="4"/>
<field name="" start="3" end="3"/>
<field name="PF" start="2" end="2"/>
<field name="" start="1" end="1"/>
<field name="CF" start="0" end="0"/>
</flags>

<reg name="eax" bitsize="32" type="int32" regnum="0"/>
<reg name="ecx" bitsize="32" type="int32"/>
<reg name="edx" bitsize="32" type="int32"/>
<reg name="ebx" bitsize="32" type="int32"/>
<reg name="esp" bitsize="32" type="data_ptr"/>
<reg name="ebp" bitsize="32" type="data_ptr"/>
<reg name="esi" bitsize="32" type="int32"/>
<reg name="edi" bitsize="32" type="int32"/>

<reg name="eip" bitsize="32" type="code_ptr"/>
<reg name="eflags" bitsize="32" type="i386_eflags"/>

<reg name="cs" bitsize="32" type="int32"/>
<reg name="ss" bitsize="32" type="int32"/>
<reg name="ds" bitsize="32" type="int32"/>
<reg name="es" bitsize="32" type="int32"/>
<reg name="fs" bitsize="32" type="int32"/>
<reg name="gs" bitsize="32" type="int32"/>

<!-- Segment descriptor caches and TLS base MSRs -->

<!--reg name="cs_base" bitsize="32" type="int32"/>
<reg name="ss_base" bitsize="32" type="int32"/>
<reg name="ds_base" bitsize="32" type="int32"/>
<reg name="es_base" bitsize="32" type="int32"/-->
<reg name="fs_base" bitsize="32" type="int32"/>
<reg name="gs_base" bitsize="32" type="int32"/>
<reg name="k_gs_base" bitsize="32" type="int32"/>

<flags id="i386_cr0" size="4">
<field name="PG" start="31" end="31"/>
<field name="CD" start="30" end="30"/>
<field name="NW" start="29" end="29"/>
<field name="AM" start="18" end="18"/>
<field name="WP" start="16" end="16"/>
<field name="NE" start="5" end="5"/>
<field name="ET" start="4" end="4"/>
<field name="TS" start="3" end="3"/>
<field name="EM" start="2" end="2"/>
<field name="MP" start="1" end="1"/>
<field name="PE" start="0" end="0"/>
</flags>

<flags id="i386_cr3" size="4">
<field name="PDBR" start="12" end="31"/>
<!--field name="" start="3" end="11"/>
<field name="WT" start="2" end="2"/>
<field name="CD" start="1" end="1"/>
<field name="" start="0" end="0"/-->
<field name="PCID" start="0" end="11"/>
</flags>

<flags id="i386_cr4" size="4">
<field name="VME" start="0" end="0"/>
<field name="PVI" start="1" end="1"/>
<field name="TSD" start="2" end="2"/>
<field name="DE" start="3" end="3"/>
<field name="PSE" start="4" end="4"/>
<field name="PAE" start="5" end="5"/>
<field name="MCE" start="6" end="6"/>
<field name="PGE" start="7" end="7"/>
<field name="PCE" start="8" end="8"/>
<field name="OSFXSR" start="9" end="9"/>
<field name="OSXMMEXCPT" start="10" end="10"/>
<field name="UMIP" start="11" end="11"/>
<field name="LA57" start="12" end="12"/>
<field name="VMXE" start="13" end="13"/>
<field name="SMXE" start="14" end="14"/>
<field name="FSGSBASE" start="16" end="16"/>
<field name="PCIDE" start="17" end="17"/>
<field name="OSXSAVE" start="18" end="18"/>
<field name="SMEP" start="20" end="20"/>
<field name="SMAP" start="21" end="21"/>
<field name="PKE" start="22" end="22"/>
</flags>

<flags id="i386_efer" size="8">
<field name="TCE" start="15" end="15"/>
<field name="FFXSR" start="14" end="14"/>
<field name="LMSLE" start="13" end="13"/>
<field name="SVME" start="12" end="12"/>
<field name="NXE" start="11" end="11"/>
<field name="LMA" start="10" end="10"/>
<field name="LME" start="8" end="8"/>
<field name="SCE" start="0" end="0"/>
</flags>

<reg name="cr0" bitsize="32" type="i386_cr0"/>
<reg name="cr2" bitsize="32" type="int32"/>
<reg name="cr3" bitsize="32" type="i386_cr3"/>
<reg name="cr4" bitsize="32" type="i386_cr4"/>
<reg name="cr8" bitsize="32" type="int32"/>
<reg name="efer" bitsize="32" type="i386_efer"/>

<reg name="st0" bitsize="80" type="i387_ext"/>
<reg name="st1" bitsize="80" type="i387_ext"/>
<reg name="st2" bitsize="80" type="i387_ext"/>
<reg name="st3" bitsize="80" type="i387_ext"/>
<reg name="st4" bitsize="80" type="i387_ext"/>
<reg name="st5" bitsize="80" type="i387_ext"/>
<reg name="st6" bitsize="80" type="i387_ext"/>
<reg name="st7" bitsize="80" type="i387_ext"/>

<reg name="fctrl" bitsize="32" type="int" group="float"/>
<reg name="fstat" bitsize="32" type="int" group="float"/>
<reg name="ftag" bitsize="32" type="int" group="float"/>
<reg name="fiseg" bitsize="32" type="int" group="float"/>
<reg name="fioff" bitsize="32" type="int" group="float"/>
<reg name="foseg" bitsize="32" type="int" group="float"/>
<reg name="fooff" bitsize="32" type="int" group="float"/>
<reg name="fop" bitsize="32" type="int" group="float"/>
<!--/feature>
<feature name="org.gnu.gdb.i386.32bit.sse"-->
<vector id="v4f" type="ieee_single" count="4"/>
<vector id="v2d" type="ieee_double" count="2"/>
<vector id="v16i8" type="int8" count="16"/>
<vector id="v8i16" type="int16" count="8"/>
<vector id="v4i32" type="int32" count="4"/>
<vector id="v2i64" type="int64" count="2"/>
<union id="vec128">
<field name="v4_float" type="v4f"/>
<field name="v2_double" type="v2d"/>
<field name="v16_int8" type="v16i8"/>
<field name="v8_int16" type="v8i16"/>
<field name="v4_int32" type="v4i32"/>
<field name="v2_int64" type="v2i64"/>
<field name="uint128" type="uint128"/>
</union>
<flags id="i386_mxcsr" size="4">
<field name="IE" start="0" end="0"/>
<field name="DE" start="1" end="1"/>
<field name="ZE" start="2" end="2"/>
<field name="OE" start="3" end="3"/>
<field name="UE" start="4" end="4"/>
<field name="PE" start="5" end="5"/>
<field name="DAZ" start="6" end="6"/>
<field name="IM" start="7" end="7"/>
<field name="DM" start="8" end="8"/>
<field name="ZM" start="9" end="9"/>
<field name="OM" start="10" end="10"/>
<field name="UM" start="11" end="11"/>
<field name="PM" start="12" end="12"/>
<field name="FZ" start="15" end="15"/>
</flags>

<reg name="xmm0" bitsize="128" type="vec128"/>
<reg name="xmm1" bitsize="128" type="vec128"/>
<reg name="xmm2" bitsize="128" type="vec128"/>
<reg name="xmm3" bitsize="128" type="vec128"/>
<reg name="xmm4" bitsize="128" type="vec128"/>
<reg name="xmm5" bitsize="128" type="vec128"/>
<reg name="xmm6" bitsize="128" type="vec128"/>
<reg name="xmm7" bitsize="128" type="vec128"/>

<reg name="mxcsr" bitsize="32" type="i386_mxcsr" group="vector"/>
</feature>