一种在用户态下调试驱动程序的方法与流程

文档序号:15229746发布日期:2018-08-21 19:15阅读:492来源:国知局

本发明属于嵌入式领域,特别涉及一种在用户态下调试驱动程序的方法。



背景技术:

本发明涉及到嵌入式领域中驱动程序调试的解决方案。嵌入式产品开发的过程往往是根据具体的应用去自行设计开发板,然后将嵌入式系统移植到开发板上运行,这就需要嵌入式系统对具体开发板进行硬件适配,而板级支持包(硬件驱动程序)的开发是硬件适配中的一个重要环节。

好的调试工具对有效、快速地进行硬件驱动程序适配起着重要作用。由于嵌入式系统自身的特点,使得开发过程中不得不使用交叉调试,即调试工具和被调试的程序运行在不同的机器上(宿主机和目标机),这种复杂性使得驱动的调试工作变得困难。目前,嵌入式系统的驱动调试大都采用硬件调试器,而这些硬件调试器往往价格昂贵,所需环境比较复杂。

系统驱动程序调试与普通应用程序调试有着很大的不同,普通应用程序一般直接通过gdb调试程序就可以完成调试,但系统内核和驱动程序却不能,这是因为gdb的正常运行是以内核为基础的。现如今,在驱动开发中常用的直接或间接的调试手段有以下几种:

1.、利用打印信息、/proc文件系统等方法:这是一种最简单、最基本的调试手段。它通过在程序中添加额外的信息打印代码,借助程序运行时打印出的信息来对代码执行过程进行分析,进而推断错误所在。但这种调试方法的缺点是过于繁琐,需要不停的编译程序、烧写程序,并且当大量使用打印信息调试时,会大大降低系统性能。

2、使用模拟器调试:模拟器通过模拟目标机来进行调试,它可以模拟多种嵌入式开发板,支持多种cpu指令集。在模拟器上不仅可以调试驱动程序,还可以调试操作系统内核程序,但它的缺点也很明显,模拟器只是对系统硬件进行了一定程度的模拟,与真实硬件存在较大差别,并不适合实际开发过程中的调试。

3、使用kgdb调试:这是linux操作系统下的一种内核调试工具,因为gdb无法对驱动程序进行调试,因此linux加入了kgdb,它实际上是一个内核补丁,并且利用了gdb程序,可以很方便地在源码级上实现对linux内核进行调试;使用kgdb调试驱动程序可以像调试应用程序一样,执行设置断点、检测变量值、单步运行等操作。它的调试功能十分强大,缺点是仅仅只适用于linux内核,对于其他嵌入式操作系统则无法调试。

4、利用硬件调试:这种调试方法虽然功能强大,但硬件要求较高,比如jtag硬件调试,它只适用于支持jtag技术的目标板,并且jtag调试器必须提供主机调试器和目标机上的调试代理,并设计调试协议。这种jtag调试系统要求目标机的运行环境已经建立,调试代理作为目标机操作系统管理下运行的进程。当目标机还未建立运行环境,甚至是没有任何程序的裸机时,jtag无法实现调试。



技术实现要素:

发明目的:针对现有技术中存在的问题,本发明提供一种纯软件的驱动调试技术,无需硬件调试器的辅助,可以降低系统开发成本,提高开发速度的在用户态下调试驱动程序的方法。

技术方案:为解决上述技术问题,本发明提供一种在用户态下调试驱动程序的方法,具体步骤如下:

(1)动态库向系统注册虚拟接口,并创建io调用管理线程、内核消息队列、线程消息队列;

(2)应用程序通过系统调用接口陷入到系统内核程序;

(3)内核程序调用已注册成功位于动态库内的虚拟接口;

(4)虚拟接口将应用程序内的信息通过线程消息队列传递给io调用管理线程;

(5)唤醒io调用管理线程,并通过内核消息队列将消息传递给虚拟接口;

(6)虚拟接口收到消息,并解析出返回值,将返回值返还给应用程序;

(7)应用程序调用成功。

进一步的,所述步骤(4)中虚拟接口将应用程序内的信息通过线程消息队列传递给io调用管理线程的具体步骤如下:

(4.1)虚拟接口判断应用程序是否带有参数,如果是则将参数打包成消息结构体,如果不是则构造空消息结构体;

(4.2)虚拟接口通过线程消息队列将消息结构体和空消息结构体传递给io调用管理线程。

进一步的,所述步骤(5)中唤醒io调用管理线程,并通过内核消息队列将消息传递给虚拟接口的具体步骤如下:

(5.1)io调用管理线程被唤醒并执行驱动接口,由于io调用管理线程处于用户态,因此驱动接口也处于用户态;

(5.2)驱动接口执行完毕;

(5.3)io调用管理线程判断驱动接口是否带有返回值,如果是则将返回值打包成消息结构体,如果不是则构造空消息结构体;

(5.4)io调用管理线程通过内核消息队列将消息传递给虚拟接口。

与现有技术相比,本发明的优点在于:

本发明在用户态下面构建驱动实现本体,包括系统io接口实现和中断服务程序实现;用户态下面的驱动本体和内核态的系统io接口或者中断服务入口有通讯关联;定义了一种在用户态下面的驱动本体与内核态的系统io接口或者中断服务入口进行通讯的消息格式。系统的io接口或者中断服务程序响应,可以激活用户态下的驱动程序本体响应;调试软件调试用户态下面的驱动本体,可以查看内核态下的寄存器值。调试软件调试用户态下面的驱动本体,驱动程序结果最终可以回归到内核态相应调用位置,以维持系统驱动的功能完整性。

本发明极大减少驱动开发人员的工作量,主要体现在驱动代码修改方面,使用本发明,系统驱动开发人员开发驱动时只需链接调试库,同时使用调试库提供的相关接口,即可进行gdb调试,用户态驱动本体的构建也仅仅只需少量代码的修改即可完成。

本发明调试功能强大,调试驱动程序与调试普通应用程序一样,支持断点设置、单步执行、进入执行、全速运行、查看变量值,支持多线程调试,支持中断嵌套的中断调试。

本发明开发成本低,采用纯软件技术进行调试,不需要硬件调试器(如jtag)的辅助,避免搭建复杂的硬件调试环境。

附图说明

图1为本发明的总体流程图;

图2为实施例中系统io调试的工作流程图;

图3为实施例中系统io调试的最终工作流程图;

图4为实施例中两个消息队列的工作流程图;

图5为实施例中中断调试的工作流程图。

具体实施方式

下面结合附图和具体实施方式,进一步阐明本发明。

为了解决上述几种传统驱动调试手段的缺陷,本发明分析了现有技术的不足,提供了一种在操作系统下,利用gdb调试驱动程序的方法。目前gdb程序不能调试驱动程序的原因包括以下几种:

1、gdb程序不能调试内核模块。

2、gdb程序不能调试操作系统向驱动提供的io接口。

3、gdb程序不能调试中断服务程序。

因此,想要利用gdb调试驱动程序,需要解决上述三种问题。

本发明的解决思路是:

将内核态的驱动程序本体转化为用户态,并采用中间线程转换的思想。

建立一个动态库,动态库内提供设备注册、中断服务程序注册的虚拟接口,将驱动程序内设备注册和中断服务程序注册的接口替换为动态库内的相关接口。

在动态库内,注册设备或注册中断服务程序的虚拟接口,会向系统注册虚拟的系统io或中断服务程序,并创建中间服务线程。

当应用程序需要调用系统io时,实际会调用到动态库内虚拟的系统io,该虚拟系统io会唤醒中间服务线程,在中间服务线程中调用真正的系统io,此时系统io就会运行在中间服务线程上下文,即运行在用户态。

当系统产生中断时,实际会调用到动态库内虚拟的中断服务接口,虚拟的中断服务接口里面会唤醒中断服务线程,在中断服务线程中则会调用真正的中断服务程序,此时中断服务程序就会运行在线程上下文内,即将中断服务程序转化为用户态。

以上方式的基本思想是将设备注册、中断服务程序注册、系统io执行、中断服务程序执行放到用户态,模拟一个应用程序的执行效果,因为gdb可以调试用户态的应用程序,所以也可以调试用户态下的驱动程序。

具体的,本发明所述的整体工作流程如图1所示:

1.动态库向系统注册虚拟接口,并创建io调用管理线程、内核消息队列、线程消息队列;

2.应用程序通过系统调用接口陷入到系统内核程序;

3.内核程序调用已注册成功位于动态库内的虚拟接口;

4.虚拟接口判断应用程序是否带有参数,如果是则将参数打包成消息结构体,如果不是则构造空消息结构体;

5.虚拟接口通过线程消息队列将消息结构体传递给io管理线程;

6.io管理线程被唤醒并执行驱动接口,由于io管理线程处于用户态,因此驱动接口也处于用户态;

7.驱动接口执行完毕;

8.io管理线程判断驱动接口是否带有返回值,如果是则将返回值打包成消息结构体,如果不是则构造空消息结构体;

9.io管理线程通过内核消息队列将消息传递给虚拟接口;

10.虚拟接口收到消息,并解析出返回值,将返回值返还给应用程序;

11.应用程序调用成功。

下面以can设备为例,说明用户态驱动调试技术的具体原理。

一、系统io的调试方法

在创建can设备驱动时,需要向系统内核注册三个io接口,注册成功后这三个io接口由系统内核管理,此时的结构框图如图2所示。

图2这种模式下,funca、funcb、funcc三个接口处于驱动层,无法直接利用gdb进行调试;但如果将驱动代码构建为用户态,并建立动态库,在动态库内创建一个io管理线程以及向系统内核注册三个虚拟的系统io接口(funca-、funcb-、funcc-),用这个io管理线程来管理funca-、funcb-、funcc-与funca、funcb、funcc这两者之间的调用关系。此时,由于用户态线程可以通过gdb调试,那么使用这种转换方法就可以解决系统io接口调试的问题,最终实现的框架如图3所示。

二、同步机制与参数返回值的传递

当系统内核调用io接口时,会涉及到动态库内虚拟的io接口与真实的驱动io接口间参数和返回值的传递过程,因此需要协调两者之间的传递过程。本发明使用两个消息队列来解决这个问题。这两个消息队列为:

线程消息队列:负责虚拟io接口与驱动io接口间参数的传递;

内核消息队列:负责虚拟io接口与驱动io接口间返回值的传递。

为了支持多个io接口调用一个io管理线程,在消息队列创建时,还需要将这两个消息队列的模式选择为先进先出的模式。

两个消息队列的工作流程如图4所示。

1.io管理线程一直处于阻塞在线程消息队列中的状态,直到线程消息队列接收到消息;

2.内核调用funca-时,会构造一个消息,此消息需要包含接口的参数。在构造完成之后,此消息会被发送到线程消息队列里。io管理线程收到消息后得以向下运行,并去调用真正的驱动接口funca。与此同时,funca-会处于阻塞在内核消息队列中的状态;

3.当funca执行完成之后,io线程会再次构造一个消息,将funca返回值发送到内核消息队列,此时funca-收到消息,得以继续运行并把返回值返回给内核。

三、消息的格式管理

对于不同的内核接口(kerfunca,kerfuncb,kerfuncc),其参数的类型,个数,返回值类型等均不相同,因此需要定义合适的消息格式,才能让io处理线程准确的获得需要执行的接口以及其参数。

本发明使用的方法是:在动态库中定义一个debugmsg的结构体,其内部成员主要有:

系统io接口类型;

系统io接口参数;

系统io接口返回值。

其中,io接口类型是一个枚举类型,它包含的了所有与当前调试驱动相关的内核接口序号。参数和返回值是一个联合体,这个联合体包含了所有内核接口的参数与返回值。

四、中断调试方法

中断服务程序调试的主体思路与系统io接口调试类似,也是使用线程做中间层管理中断服务程序的调用。实现框架如图4所示。

但中断服务线程与系统io接口调试时的处理方式存在以下的不同:

1.线程数量

对于系统io接口的调试,只需要一个线程,此线程阻塞等待消息,然后根据消息内容执行对应的系统io接口。

对于中断调试,首先,中断线程不能与系统io管理线程共用,这是因为中断的处理应该是能打断正在执行的系统io接口的,共用线程无法实现这一点。另外,为了支持中断的嵌套机制,本发明的处理方法是为驱动里绑定的每一个中断服务程序创建一个中断调用线程,线程的优先级与中断的优先级对应。

2.线程的处理方式

对于系统io接口调试,由于kerfunca是可以阻塞的,因此funca-内可以阻塞等待用户线程处理完,将处理完成的数据返回给内核。

而中断服务程序是不能阻塞的,因此本方案的处理机制是,当系统产生中断,并调用中断服务程序irqa-时,irqa-会先关闭对应的中断,同时发送信号量,唤醒对应的中断线程,此后,irqa-返回,通知内核中断已经处理完成。相应的,中断服务线程收到信号量时,会调用真正的中断服务程序irqa。等irqa执行完成后,中断服务线程才会再次打开对应中断,保证系统的正常运行。

3.参数的传递方式

对于系统io接口调试,系统io接口的参数传递使用的是debugmsg的结构体,而在中断线程里,由于中断服务程序的参数类型和参数个数是固定的,因此中断服务程序的参数直接在创建中断服务线程的时候,作为线程参数传入到中断服务线程中。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1