GDB-sim模拟器结构剖析

来源 :新校园·上旬刊 | 被引量 : 0次 | 上传用户:punk123456
下载到本地 , 更方便阅读
声明 : 本文档内容版权归属内容提供方 , 如果您对本文有版权争议 , 可与客服联系进行内容授权或下架
论文部分内容阅读
  摘要:本文从结构上剖析了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著.机械工业出版社.
其他文献