⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 7.htm

📁 关于linux嵌入式的极好的详解
💻 HTM
📖 第 1 页 / 共 2 页
字号:
    49 #ifdef CONFIG_X86_REMOTE_DEBUG <br>

50 gdb_debug_hook * linux_debug_hook; <br>

前面的条件宏定义是Linux内核的编译选项,在自定义内核编译选项的时候,选中KGDB的支 <br>

持,这个宏被定义。 <br>

&#61548;    static void gdb_interrupt(int irq, void* dev_id, struct pt_regs* reg <br>

  <br>

); <br>

gdb_interrupt()函数是相对于该串口的中断服务程序,通过这个中断服务程序利用read_ <br>

data_bfr()从串口读取数据,填充缓冲区。 <br>

&#61548;    int gdb_hook(void); <br>

该函数调用gdb_serial_setup()函数初始化串口,然后向系统注册中断服务程序gdb_inte <br>

rrupt,运行set_debug_traps()函数,设置断点。在这个函数的运行过程中取得和本地主 <br>

机的连接。 <br>

6.2.3 内核进入调试状态的路径 <br>

让内核进入调试状态有两种方法,一种是通过在内核启动的时候向内核传入参数,这个时 <br>

候可以调试系统启动过程内核的运行状况;另外一种方法是在内核完全导入系统正常运行 <br>

的情况下,通过使用一个gdbstart工具将驱动串口设备,内核的控制权交给本地主机,从 <br>

而进入系统调用的调试状态。可以通过它监控每一个系统调用在内核的运行过程。 <br>

6.2.3.1 系统启动的时候向内核传递参数 <br>

我们知道,在Linux启动的时候,可以给Linux内核传递进去一些参数,Linux内核在运行时 <br>

也就可以根据传入的入口参数决定运行时的一些状况。比如说,给内核传递root=/dev/hd <br>



a4,就表示内核在启动之后,把/dev/hda4作为根文件系统装载上来。对于KGDB,定义了三 <br>

个可以向内核传递的参数,用来指定本地主机和远程主机进行连接的方法。这三个参数是 <br>

gdb,gdbttyS和gdbbaud。 <br>

gdb参数表示在内核启动的时候就需要进行内核的调试,也就是说,内核并不会自己运行完 <br>

,而是在一定的时候会停下来,将控制权交给远程的GDB来控制执行。 <br>

gdbttyS是用来指定本地机器和远程主机需要连接的串口号。gdbbaud是该串口连接的数据 <br>

传输波特率。在串口上进行连接的时候,需要双方的波特率相同才可能正确连接。这两个 <br>

参数需要在后面调用gdb_serial_setup()函数将指定的串口初始化。 <br>

然后,系统进入gdb_hook()函数,调用gdb_serial_setup()函数和注册中断处理函数,并 <br>

且运行set_debug_traps()交出控制权,从而进行内核启动过程的调试。 <br>

整个过程可以参看下面的源代码: <br>

1)init/main.c 中的一段: <br>

———————————————————————————init/main.c— <br>

394 #ifdef CONFIG_X86_REMOTE_DEBUG <br>

395 if (!strcmp(line,"gdb")) {/*判断内核参数gdb*/ <br>

396      gdb_enter = 1; <br>

397      continue; <br>

398 } <br>

399 if (!strcmp(line,"gdbttyS=")) { <br>

400      gdb_ttyS = simple_strtoul(line+8,NULL,10); <br>

401      continue; <br>

402 } <br>

402 } <br>

403 if (!strcmp(line,"gdbbaud=")) { <br>

404      gdb_baud = simple_strtoul(line+8,NULL,10); <br>

405      continue; <br>

406 } <br>

407 #endif /* CONFIG_X86_REMOTE_DEBUG */ <br>

———————————————————————————————— <br>

2)gdb_hook()函数: <br>

        该函数定义在drivers/char/gdbserial.c中,下面是它的一些片断: <br>

—————————————————————————gdbserial.c—— <br>

170 int gdb_hook(void) <br>

…… <br>

178 if((ser = gdb_serial_setup(gdb_ttyS, gdb_baud)) == 0) { <br>

…… <br>

183     gdb_port = ser->port; <br>

184     gdb_irq = ser->irq; <br>

185 <br>

186     if (ser->info != NULL) <br>

187     { <br>

…… <br>

193         gdb_serial_setup(gdb_ttyS, gdb_baud) ; <br>

194     } <br>

195 <br>

195 <br>

196     retval = request_irq(gdb_irq, <br>

197                      gdb_interrupt, <br>

198                      SA_INTERRUPT, <br>

199                      "GDB-stub", NULL); <br>

…… <br>

211     set_debug_traps() ; <br>

…… <br>

217     printk("Waiting for connection from remote gdb... ") ; <br>

218     breakpoint() ; <br>

219     gdb_null() ; <br>

220 <br>

221     printk("Connected.\n"); <br>

222 <br>

223     return(0) ; <br>

224 <br>

225 } /* gdb_hook_interrupt2 */ <br>

    ———————————————————————————————— <br>

  <br>

后来的处理都交给handle_exception()函数了,handle_exception和主机的GDB连接,获 <br>

取控制信息,然后控制本地的内核的运行。 <br>

6.2.3.2 使用gdbstart将系统控制权交出 <br>

使用gdbstart是让系统内核交出控制权的另一种方法,通过给gdbstart传入需要连接的串 <br>



口的两个参数信息(串口号和传输波特率),在内核的控制权交出之后和本地的GDB建立连 <br>

接,从而可以监控每一次进入系统调用的时候在内核运行的情况。gdbstart是一个由KGDB <br>

提供的工具,源程序放在arch/i386/kernel/gdbstart.c里面。 <br>

这种交出控制权的方法和刚才所描述的不同,它是采用ioctl系统调用进入的。对需要连接 <br>

的串口调用ioctl系统调用,引发初始化串口和进入gdb_hook()函数。 <br>

在gdbstart.c里面: <br>

——————————————————————————gdbstart.c—— <br>

112     fil = open(tty_name, O_RDWR) ;//打开串口设备 <br>

…… <br>

129     sync() ; <br>

130     rslt = ioctl(fil, TIOCGDB, 0);//进入ioctl过程 <br>

    …… <br>

    ———————————————————————————————— <br>

    进入到ioctl过程中后,程序运行到drivers/char/serial.c中的判断如何对串口进行控 <br>

  <br>

的过程,在这里,给kgdb需要使用的串口信息赋值,并且进入gdb_hook(),开始了内核 <br>

的调试。 <br>

——————————————————————drivers/char/serical.c—— <br>

2479 #ifdef CONFIG_X86_REMOTE_DEBUG <br>

2480                 case TIOCGDB: <br>

2481                    gdb_ttyS = MINOR(tty->device) & 0x03F ; <br>

2482                    gdb_baud = tty_get_baud_rate(tty) ; <br>



2483                         return gdb_hook(); <br>

2484 #endif <br>

    ———————————————————————————————— <br>

在需要进行调试的时候,运行gdbstart [-s speed] [-t tty-dev]命令,就可以和本地的 <br>

gdb的remote方式连接,从而进入调试过程。当然在gdb里面需要设定对应的串口和同样的 <br>

传输波特率才行。 <br>

  <br>

6.2.4 Linux内核调试过程示例 <br>

这里给出一次Linux内核调试过程示例,对这种内核调试环境也有一种直观的理解。 <br>

在远程主机上,建立一个脚本文件 debug,用于启动远程主机上的stub程序,交出内核运 <br>

行的控制权。 <br>

————————————————————————debug script——— <br>

#!/bin/sh <br>

gdbstart -s 38400 -t /dev/ttyS0 <<EOF <br>

  <br>

EOF <br>

———————————————————————————————— <br>

表示通过/dev/ttyS0,波特率为38400的速度进行连接。 <br>

这个时候,在本地主机运行gdb,如下所示(vmlinux是内核符号表): <br>

    然后就可以随意使用gdb的命令了。比如说需要打印出外部变量jiffies的值,那么运行 <br>

  <br>

[root@cims /usr/src/linux/]#gdb vmlinux <br>



GNU gdb 19991004 <br>

Copyright 1998 Free Software Foundation, Inc. <br>

GDB is free software, covered by the GNU General Public License, and you are <br>

  <br>

welcome to change it and/or distribute copies of it under certain conditions. <br>

  <br>

Type "show copying" to see the conditions. <br>

There is absolutely no warranty for GDB.  Type "show warranty" for details. <br>

This GDB was configured as "i386-redhat-linux"... <br>

(gdb)set remotebaud 38400 <br>

(gdb)target remote /dev/ttyS0 <br>

breakpoint() at i386-stub.c:750 <br>

750 } <br>

(gdb) <br>

(gdb)p jiffies <br>

$1 = 0x23ab <br>

…… …… <br>

    又假如说想知道当前的进程是什么(使用的是task_struct变量),地址存放在eip寄存 <br>

  <br>

中。那么可以如下操作: <br>

(gdb)info registers <br>

…… …… <br>

…… …… <br>

eip: 0xc014b0e8  –1072385816 <br>

…… …… <br>

(gdb)p (struct task_struct)*0xc014b0e8 <br>

$2 = {state = 0xbffffaa8, flags = 0xc010bf64, sigpending = 0xbffffccf, <br>

addr_limit = {seg = 0xbffffb70}, exec_domain = 0xbffffb60, need_resched = 0x0, <br>

  <br>

counter = 0xbffffccf, priority = 0xbffffaa8, avg_slice = 0xa, has_cpu = 0x2b, <br>

  <br>

…… …… <br>

    如果想调试系统调用的情况,可以在系统调用的入口设置断点。假如需要调试unlink系 <br>

  <br>

调用,那么可以如下操作: <br>

(gdb)break sys_unlink <br>

Breakpoint 1 at 0xc014b0e8: file /usr/src/linux-2.3.35/include/asm/current.h, <br>

line 9. <br>

(gdb)continue <br>

    这个命令让远程机器上的内核运行下去,然后可以在远程机器上触发一个unlink的系统 <br>

  <br>

用,比如说删除一个文件。当发生这件事情的时候,系统遇到断点,交出控制权,进入如 <br>

下界面: <br>

(gdb)continue <br>

Continuing. <br>

Continuing. <br>

  <br>

Breakpoint 2, sys_unlink (pathname=0xbffffccf "mm") <br>

    at /usr/src/linux-2.3.35/include/asm/current.h:9 <br>

9               __asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL)); <br>

    触发了断点,就可以进行系统调用在内核的调试了。 <br>

6.3 RTLinux的调试环境的开发设想 <br>

根据KGDB的设计,可以考虑如何在RTLinux平台上搭建调试平台。在RTLinux上搭建调试平 <br>

台和Linux内核调试不同,这里要进行的是调试RT Linux的实时任务,这里的调试就应该像 <br>

是对一般可执行程序的调试一样,对插入的模块进行调试,检查监视每一个实时任务线程 <br>

的情况。 <br>

这里,我提出一种可以用来对实时任务进行调试的方案,利用RTLinux的特性,可以作如下 <br>

的设计: <br>

1. 使用RT Linux的FIFO设备作为调试的连接设备。gdb使用远程调试的方法,和一个FIFO <br>

相连接,从FIFO中获取数据,并且通过FIFO设备发出实时任务运行下去指令。 <br>

2. 针对FIFO设备实现基本的stub必要的函数接口,就是在6.1.3提供的那些函数如getDeb <br>

ugChar(),putDebugChar()等等。然后实现set_debug_traps()、breakpoint()、handle_ <br>

exception()等函数。 <br>

3. 在需要调试的实时任务模块中,使用breakpoint()函数增加一个断点。在运行到break <br>

point()的时候,触发一个中断,进入中断处理程序,从而将实时任务模块的控制权交出。 <br>

  <br>

  <br>

  <br>



    这里仍然是根据GDB的远程调试功能的构思,编写出适合于RTLinux 实时任务的调试环  <br>

  <br>

,对使用RT Linux进行实时环境下的编程很有帮助。 <br>

  <br>

6.4 小结 <br>

本章详细介绍了如何利用GDB搭建Linux内核的远程调试环境,从而进行Linux内核的调试过 <br>

程。从GDB的原理到Kernel Debugger的实现,到在RT Linux环境下的调试环境的建立的设 <br>

想。 <br>

调试环境是基于Linux的嵌入式系统开发工具链的重要部分,使用该调试环境,是实现内核 <br>

个性化定制的必要条件。 <br>

  <br>

-- <br>

紅酥手 黃滕酒 滿城春色尃m澚  <br>

 |風惡 歡情薄 一懷愁緒 幾年離索 <br>

錯 錯 錯 ! <br>

春如舊 人空瘦 満I奂t 捧o綃透 <br>

桃花落 槌f亻w 山盟雖在 鍟\

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -