论文部分内容阅读
摘要:本文从结构上剖析了GDB—sim模拟器,对configure文件进行了解释、对动态的程序接口、静态的数据结构进行了分析。在硬件结构模拟上对cpu、内存、总线、设备的模拟及在行为模拟上对CPU取指令(fetch)、指令解码(decode)、指令执行(execute)行为和外设行为的模拟分别进行了描述。
关键词:模拟器、GDB、sim、CPU模拟、硬件模拟、设备模拟
一、引言
GDB,作为一种很优秀的开源调试器,是GNU开发工具链中很重要的产品,由于其适用于多种平台及对多种cpu的支持而受到普遍的关注。在PC上进行开发嵌入式程序时(例如mips、arm程序),不能在pc的x86平台上进行调试,只能通过仿真器连接开发板进行调试或通过GDB内嵌的sim模拟器进行调试。在进行非驱动开发时,使用内嵌sim模拟器调试是一个较好的选择。本文将对sim模拟器的结构及运行进行剖析。
二、配置及编译
产生可执行程序的过程为配置、编译、安装。
该模拟器支持ARM、MIPS、PowerPC、Hitachi Super-H等cpu。在编译前要通过configure来指定target。例如:
./configure --target=mips
在configure后,执行命令make。产生可执行文件run和库文件libsim.a。
最后通过执行命令make install安装run到usr/local/bin目录下和安装libsim.a到usr/local/lib目录下。
在这三个过程中用到了configure和Makefile两个文件。
1.configure分析
GNU的模拟器支持多类型的CPU,通过configure的target选项来配置不同的CPU系统。
例如:在linux或cygwin下配置mips模拟器执行命令
./configure --target=mips
configure主要作用:
根据target决定模拟器挂载的设备
生成相关环境变量(包括源文件路径、可执行文件路径、库文件路径等)读入Makefile.in文件,根据配置生成Makefile文件。
相关部分代码:
case "${target}" in
mips*-*-*) //target=mips的设置
# The MIPS simulator can only be compiled by gcc.
sim_target=mips
only_if_gcc=yes
extra_subdirs="${extra_subdirs} igen"
;;
2.Makefile分析
Makefile.in文件是与target无关的,经configure生成的Makefile才是和具体target相关的通过make来生成相应的模拟器。在makefile中含有target决定编译的路径、编译的文件。
Makefile主要作用:
配置编译环境变量
编译.c源文件为.o目标文件
编译单机版模拟器run
编译库文件libsim.a供gdb调用
三、模拟器版本
模拟器有单机版和gdb内嵌版两种版本。在gdb内嵌版中,模拟器给gdb提供了一套程序接口函数,供gdb驱动使用。在单机版中,主函数也会调用这套接口函数,脱离GDB的控制独立运行。
1.单机版
在sim/common/nrun.c 有一个main主函数,编译后产生run可执行程序,控制模拟器的运行,不受gdb控制。
使用方法:
./run 目标程序 目标程序参数
编译后的run程序在make install后,会根据target不同名称,更改为target-run(例如mips-run、Lx5280-run)拷贝到bin目录下。
2.gdb内嵌版
内嵌在gdb中,被gdb调用
在gdb中使用命令
(gdb) target sim
连接gdb内嵌模拟器
四、模拟器程序接口
模拟器给gdb提供了一套程序接口函数,。在单机版中,主函数也会调用这套接口函数。
1.供单机版main函数和gdb内嵌版调用的接口
sim_open() 打开模拟器,建立相关的数据结构
sim_load() 装入运行在模拟硬件上的bfd文件
sim_create_inferior() 模拟器初始化,设置寄存器初始值
sim_resume() 模拟器模拟运行
sim_stop() 请求模拟器停止运行
sim_stop_reason() 读模拟器停止原因
sim_close() 模拟器停止,释放数据结构
sim_do_command() 特殊命令的接口
2.供gdb调试调用的接口
sim_read() 读被模拟memory
sim_write() 写被模拟memory
sim_fetch_register() 读被模拟cpu的寄存器 //需修改
sim_restore_register()写被模拟cpu的寄存器 //需修改
sim_set_breakpoint() 断点设置命令
sim_clear_breakpoint() 清除断点
sim_clear_all_breakpoints() 清除所有断点
sim_enable_breakpoint()断点有效/无效设置
sim_disable_breakpoint()禁止断点
sim_enable_all_breakpoints()使能所有断点
sim_disable_all_breakpoints()禁止所有断点
五、主要数据结构
GNU模拟器设计为对称多处理器(SMP)结构,但并不完善,不过单处理器模拟还是很成熟的。这章对模拟器中的模拟器状态结构、cpu结构、总线存储器结构作一个描述,关于cpu外设备的结构单独在3.7节描述。
1.模拟器状态sim_state结构
这里的模拟器状态结构并不是这个模拟器程序的状态,而是指一个包括cpu结构、总线存储器、设备树,及模拟器运行状态的一个根结构。
包括:cpu结构
在模拟器上运行的target程序
总线、存储器结构指针
cpu外部设备硬件树root指针
target程序断点
运行引擎engine
定时事件链表(每条指令执行前都会查询是否有定时事件方式)
模块链表(参数处理、事件队列、存储器、程序断点等模块的初始化、安装、以下、挂起、退出处理)
2.CPU数据结构_sim_cpu
这里模拟单个cpu的结构和个性行为。和移植工作密切相关。
它的结构主要包括:
通用、控制、状态、浮点寄存器。
寄存器宽度(用于读写操作)
流水线的延迟写队列pending
delay-slot状态
模拟存储器参数及指针
读写寄存器、内存方法指针
原子操作位llbit
3.总线、存储器结构_sim_core
在这里总线、存储器合并为core结构,若地址mapping 的device为NULL,则读写buffer中的模拟内存,若device不为NULL,则该地址为设备地址,读写device。程序读、写、执行、IO口可设为不同mapping,但通常指向同一mapping。
六、运行跟踪
这里围绕模拟器的动态运行,逐步分析模拟器的初始化,装载程序,运行,退出,分析模拟器的函数调用过程。
1.模拟器初始化
在这里建立一个模拟器的数据结构,并初始化。
a、申请内容空间,建立模拟器(CPU、内存、其他硬件)的数据结构。
b、根据选项配置模拟器。
c、分析被运行在模拟器上程序的结构并打开。
源码摘要:
sd = sim_open (SIM_OPEN_STANDALONE,&default_callback,NULL,argv); //生成sim结构
sim_pre_argv_init (sd, argv[0]); //初始化
sim_add_option_table(sd, NULL,mips_options);//加载mips选项
sim_parse_args (sd, argv); //参数处理
sim_do_command(sd,“memory region 0x7fff8000,0x8000”);//加载模拟内存
2.装载程序
a、分析程序的bfd文件结构。
b、装载到模拟内存上。
源码摘要:
prog_bfd = bfd_openr (name, 0); //打开bfd格式文件,读入到bfd结构中
sim_load (sd, nam, prog_bfd, 0);//装入程序到模拟内存
调用sim_analyze_program (sd, prog_name, prog_bfd);
//分析程序
调用sim_load_file( …);//装载文件
sim_create_inferior (sd, prog_bfd, prog_argv,NULL);
3.运行程序
a、运行准备,各模块resume。
b、事件预处理(查询事件链表是否有定时事件发生,若有,执行其函数)。
c、运行
取指令(根据cia,从存储器读指令)
指令解码(在idecode.c文件中idecode_issue函数解码)
指令执行(执行解码后得到的指令行为函数)
计算下条指令地址
d、判断结果,检测是否有异常或设有断点,决定是否继续运行。
源码摘要:
sim_resume (sd,1/*step*/, 0);
调用sim_module_resume (sd);//启动模拟器各模块
调用sim_events_preprocess (sd, ….);//处理cpu的事件
调用sim_events_process (sd);
调用sim_engine_run (sd, next_cpu_nr, nr_cpus, siggnal);
//支持多cpu
调用instruction_word insn = ifetch32 (SD, CPU, (CIA), (CIA)); //取指
调用AddressTranslation (vaddr, &paddr, &uncached,…);
//转换地址
调用LoadMemory (…);
调用cia = idecode_issue (sd,insn,cia); //解码、执行指令操作
调用switch (EXTRACTED32 (instruction_0,5,0))
调用 case : {nia = semantic_AND_SPECIAL (sd,instruction_0,cia);//semantics
调用do_add();//support.c
4.模拟器退出
模拟器退出比较简单,在执行各模块链表退出函数(释放各模块结构)后释放模拟器状态结构。
a、执行各模块链表退出函数。
b、释放模拟器状态结构。
c、返回。
调用函数为:
sim_close (sd,0);
七、结束语
本文介绍了GDB-sim模拟器的基本原理、基本结构及实现方法,通过本文的分析,可以了解GDB-sim模拟器的基本概念和实现方法。对构建一个特定系统的专用模拟器会有一定的帮助。
【参考文献】
[1]See MIPS Run.Dominic Sweetman,Algorithmics Ltd.
[2]MIPS SDE /FGT Programmers’ GuideMIPS Technologies,Inc.
[3]Embedded MIPS Development Guide.Green Hills Software,Inc.
[4]虚拟机的设计与实现-C/C++.Bill Blunden著.机械工业出版社.
[5]深入Java虚拟机.Bill Venners著.机械工业出版社.
关键词:模拟器、GDB、sim、CPU模拟、硬件模拟、设备模拟
一、引言
GDB,作为一种很优秀的开源调试器,是GNU开发工具链中很重要的产品,由于其适用于多种平台及对多种cpu的支持而受到普遍的关注。在PC上进行开发嵌入式程序时(例如mips、arm程序),不能在pc的x86平台上进行调试,只能通过仿真器连接开发板进行调试或通过GDB内嵌的sim模拟器进行调试。在进行非驱动开发时,使用内嵌sim模拟器调试是一个较好的选择。本文将对sim模拟器的结构及运行进行剖析。
二、配置及编译
产生可执行程序的过程为配置、编译、安装。
该模拟器支持ARM、MIPS、PowerPC、Hitachi Super-H等cpu。在编译前要通过configure来指定target。例如:
./configure --target=mips
在configure后,执行命令make。产生可执行文件run和库文件libsim.a。
最后通过执行命令make install安装run到usr/local/bin目录下和安装libsim.a到usr/local/lib目录下。
在这三个过程中用到了configure和Makefile两个文件。
1.configure分析
GNU的模拟器支持多类型的CPU,通过configure的target选项来配置不同的CPU系统。
例如:在linux或cygwin下配置mips模拟器执行命令
./configure --target=mips
configure主要作用:
根据target决定模拟器挂载的设备
生成相关环境变量(包括源文件路径、可执行文件路径、库文件路径等)读入Makefile.in文件,根据配置生成Makefile文件。
相关部分代码:
case "${target}" in
mips*-*-*) //target=mips的设置
# The MIPS simulator can only be compiled by gcc.
sim_target=mips
only_if_gcc=yes
extra_subdirs="${extra_subdirs} igen"
;;
2.Makefile分析
Makefile.in文件是与target无关的,经configure生成的Makefile才是和具体target相关的通过make来生成相应的模拟器。在makefile中含有target决定编译的路径、编译的文件。
Makefile主要作用:
配置编译环境变量
编译.c源文件为.o目标文件
编译单机版模拟器run
编译库文件libsim.a供gdb调用
三、模拟器版本
模拟器有单机版和gdb内嵌版两种版本。在gdb内嵌版中,模拟器给gdb提供了一套程序接口函数,供gdb驱动使用。在单机版中,主函数也会调用这套接口函数,脱离GDB的控制独立运行。
1.单机版
在sim/common/nrun.c 有一个main主函数,编译后产生run可执行程序,控制模拟器的运行,不受gdb控制。
使用方法:
./run 目标程序 目标程序参数
编译后的run程序在make install后,会根据target不同名称,更改为target-run(例如mips-run、Lx5280-run)拷贝到bin目录下。
2.gdb内嵌版
内嵌在gdb中,被gdb调用
在gdb中使用命令
(gdb) target sim
连接gdb内嵌模拟器
四、模拟器程序接口
模拟器给gdb提供了一套程序接口函数,。在单机版中,主函数也会调用这套接口函数。
1.供单机版main函数和gdb内嵌版调用的接口
sim_open() 打开模拟器,建立相关的数据结构
sim_load() 装入运行在模拟硬件上的bfd文件
sim_create_inferior() 模拟器初始化,设置寄存器初始值
sim_resume() 模拟器模拟运行
sim_stop() 请求模拟器停止运行
sim_stop_reason() 读模拟器停止原因
sim_close() 模拟器停止,释放数据结构
sim_do_command() 特殊命令的接口
2.供gdb调试调用的接口
sim_read() 读被模拟memory
sim_write() 写被模拟memory
sim_fetch_register() 读被模拟cpu的寄存器 //需修改
sim_restore_register()写被模拟cpu的寄存器 //需修改
sim_set_breakpoint() 断点设置命令
sim_clear_breakpoint() 清除断点
sim_clear_all_breakpoints() 清除所有断点
sim_enable_breakpoint()断点有效/无效设置
sim_disable_breakpoint()禁止断点
sim_enable_all_breakpoints()使能所有断点
sim_disable_all_breakpoints()禁止所有断点
五、主要数据结构
GNU模拟器设计为对称多处理器(SMP)结构,但并不完善,不过单处理器模拟还是很成熟的。这章对模拟器中的模拟器状态结构、cpu结构、总线存储器结构作一个描述,关于cpu外设备的结构单独在3.7节描述。
1.模拟器状态sim_state结构
这里的模拟器状态结构并不是这个模拟器程序的状态,而是指一个包括cpu结构、总线存储器、设备树,及模拟器运行状态的一个根结构。
包括:cpu结构
在模拟器上运行的target程序
总线、存储器结构指针
cpu外部设备硬件树root指针
target程序断点
运行引擎engine
定时事件链表(每条指令执行前都会查询是否有定时事件方式)
模块链表(参数处理、事件队列、存储器、程序断点等模块的初始化、安装、以下、挂起、退出处理)
2.CPU数据结构_sim_cpu
这里模拟单个cpu的结构和个性行为。和移植工作密切相关。
它的结构主要包括:
通用、控制、状态、浮点寄存器。
寄存器宽度(用于读写操作)
流水线的延迟写队列pending
delay-slot状态
模拟存储器参数及指针
读写寄存器、内存方法指针
原子操作位llbit
3.总线、存储器结构_sim_core
在这里总线、存储器合并为core结构,若地址mapping 的device为NULL,则读写buffer中的模拟内存,若device不为NULL,则该地址为设备地址,读写device。程序读、写、执行、IO口可设为不同mapping,但通常指向同一mapping。
六、运行跟踪
这里围绕模拟器的动态运行,逐步分析模拟器的初始化,装载程序,运行,退出,分析模拟器的函数调用过程。
1.模拟器初始化
在这里建立一个模拟器的数据结构,并初始化。
a、申请内容空间,建立模拟器(CPU、内存、其他硬件)的数据结构。
b、根据选项配置模拟器。
c、分析被运行在模拟器上程序的结构并打开。
源码摘要:
sd = sim_open (SIM_OPEN_STANDALONE,&default_callback,NULL,argv); //生成sim结构
sim_pre_argv_init (sd, argv[0]); //初始化
sim_add_option_table(sd, NULL,mips_options);//加载mips选项
sim_parse_args (sd, argv); //参数处理
sim_do_command(sd,“memory region 0x7fff8000,0x8000”);//加载模拟内存
2.装载程序
a、分析程序的bfd文件结构。
b、装载到模拟内存上。
源码摘要:
prog_bfd = bfd_openr (name, 0); //打开bfd格式文件,读入到bfd结构中
sim_load (sd, nam, prog_bfd, 0);//装入程序到模拟内存
调用sim_analyze_program (sd, prog_name, prog_bfd);
//分析程序
调用sim_load_file( …);//装载文件
sim_create_inferior (sd, prog_bfd, prog_argv,NULL);
3.运行程序
a、运行准备,各模块resume。
b、事件预处理(查询事件链表是否有定时事件发生,若有,执行其函数)。
c、运行
取指令(根据cia,从存储器读指令)
指令解码(在idecode.c文件中idecode_issue函数解码)
指令执行(执行解码后得到的指令行为函数)
计算下条指令地址
d、判断结果,检测是否有异常或设有断点,决定是否继续运行。
源码摘要:
sim_resume (sd,1/*step*/, 0);
调用sim_module_resume (sd);//启动模拟器各模块
调用sim_events_preprocess (sd, ….);//处理cpu的事件
调用sim_events_process (sd);
调用sim_engine_run (sd, next_cpu_nr, nr_cpus, siggnal);
//支持多cpu
调用instruction_word insn = ifetch32 (SD, CPU, (CIA), (CIA)); //取指
调用AddressTranslation (vaddr, &paddr, &uncached,…);
//转换地址
调用LoadMemory (…);
调用cia = idecode_issue (sd,insn,cia); //解码、执行指令操作
调用switch (EXTRACTED32 (instruction_0,5,0))
调用 case : {nia = semantic_AND_SPECIAL (sd,instruction_0,cia);//semantics
调用do_add();//support.c
4.模拟器退出
模拟器退出比较简单,在执行各模块链表退出函数(释放各模块结构)后释放模拟器状态结构。
a、执行各模块链表退出函数。
b、释放模拟器状态结构。
c、返回。
调用函数为:
sim_close (sd,0);
七、结束语
本文介绍了GDB-sim模拟器的基本原理、基本结构及实现方法,通过本文的分析,可以了解GDB-sim模拟器的基本概念和实现方法。对构建一个特定系统的专用模拟器会有一定的帮助。
【参考文献】
[1]See MIPS Run.Dominic Sweetman,Algorithmics Ltd.
[2]MIPS SDE /FGT Programmers’ GuideMIPS Technologies,Inc.
[3]Embedded MIPS Development Guide.Green Hills Software,Inc.
[4]虚拟机的设计与实现-C/C++.Bill Blunden著.机械工业出版社.
[5]深入Java虚拟机.Bill Venners著.机械工业出版社.