收藏 分享(赏)

第4章-调试技术.ppt

上传人:无敌 文档编号:331532 上传时间:2018-03-29 格式:PPT 页数:57 大小:533.50KB
下载 相关 举报
第4章-调试技术.ppt_第1页
第1页 / 共57页
第4章-调试技术.ppt_第2页
第2页 / 共57页
第4章-调试技术.ppt_第3页
第3页 / 共57页
第4章-调试技术.ppt_第4页
第4页 / 共57页
第4章-调试技术.ppt_第5页
第5页 / 共57页
点击查看更多>>
资源描述

1、,1,3,2,4,第4 章 调试技术,内核中的调试支持,通过打印调试,通过查询调试,通过监视调试,调试系统故障,调试器和相关工具,5,6,内核中的调试支持,内核开发者建立了许多用于支持调试的功能,以方便调试,但这些功能会导致性能下降,发行版自带内核中往往关闭了这些功能内核开发者需要这些功能,应该打开这些调试功能重新配置、编译、安装内核Kernel hacking菜单中有如下选项CONFIG_DEBUG_KERNEL该菜单中调试选项总开关,关时全关,开时并不打开下级子开关CONFIG_DEBUG_SLAB开启内存分配函数中的类型检查,可以检测内存溢出及忘记初始化错误,内核中的调试支持,CONFI

2、G_DEBUG_PAGEALLOC可定位特定内存损坏错误所在位置CONFIG_DEBUG_SPINLOCK内核将捕获未初始化自旋锁及两次解开同一锁等错误CONFIG_DEBUG_SPINLOCK_SLEEP检查拥有自旋锁时的休眠企图CONFIG_INIT_DEBUG用于初始化完成后对用于初始化的内存空间的访问检查CONFIG_DEBUG_INFO使内核的构造包含完整的调试信息,gdb需要,内核中的调试支持,CONFIG_MAGIC_SYSRQ打开“SYsRq魔法”按键CONFIG_DEBUG_STACKOVERFLOWCONFIG_DEBUG_STACK_USAGE帮助跟踪内核栈溢出CONFI

3、G_KALLSYMS出现在General setup/Standard features内核中包含用于调试上下文的符号信息,内核中的调试支持,CONFIG_IKCONFIGCONFIG_IKCONFIG_PROC出现在General setup让完整的内核配置状态包含到内核中,并可通过/proc访问CONFIG_ACPI_DEBUG出现在Power management/ACPI打开ACPI(Advanced Configuration and Power Interface)中的详细调试信息CONFIG_DEBUG_DRIVER出现在Device drivers打开驱动程序核心中的调试信息,

4、可以帮助跟踪底层支持代码中的问题,内核中的调试支持,CONFIG_SCSI_CONSTANTS出现在Device drivers/SCSI device support中,打开详细的SCSI错误消息CONFIG_INPUT_EVBUG出现在Device drivers/Input device support中,打开对输入事件的详细记录CONFIG_PROFILING出现在Profiling support中,用于系统性能的调节,但对跟踪内核挂起及相关问题也有帮助,1,3,2,4,第4 章 调试技术,内核中的调试支持,通过打印调试,通过查询调试,通过监视调试,调试系统故障,调试器和相关工具,5

5、,6,通过打印调试,Printk是内核调试中最简单有效的工具,通过在内核代码的某些关键地方放置一条printk语句,打印一些信息,即可知道运行代码的某些行为,例: printk(KERN_CRIT Im trashed; giving up on %pn, ptr);Printk的使用需要包含头文件只有在消息优先级高于控制台优先级时,信息才能出现在终端上控制台日志级别console_loglevel的初始值为DEFAULT_CONSOLE_LOGLEVE,可通过sys_syslog系统调用修改,也可通过文本文件/proc/sys/kernel/printk修改,消息日志,通过打印调试,例 如下

6、指令将控制台日志级别修改为8 # echo 8 /proc/sys/kernel/printk下表为消息日志级别,数字越小,优先级越高 日志级别 描述 KERN_EMERG 紧急事件消息 KERN_ALERT 用于需要立即采取动作的情况 KERN_CRIT 临界状态,通常涉及严重的硬件或软件操作失败 KERN_ERR 用于报告错误状态 KERN_WARNING 对可能出现问题的情况进行警告 KERN_NOTICE 有必要进行提示的情形 KERN_INFO 提示性信息 KERN_DEBUG 用于调试信息,通过打印调试,未指定消息优先级的 printk 语句缺省优先级是 DEFAULT_MESSA

7、GE_LOGLEVEL, 在 kernel/printk.c 里指定作为一个整数. 在 2.6.10 内核中, 为 KERN_WARNING。,通过打印调试,消息如何被记录printk将消息写到一个长度为_LOG_BUF_LEN(4KB1MB,默认16KB)的循环缓冲区中,然后唤醒等待消息的进程睡眠在syslog系统调用(syslog()-写、openlog()-打开日志服务、closelog()-关闭)上的进程正在读取/proc/kmsg的进程(如cat)Klogd运行时读取内核消息,并传给syslogd,后者根据/etc/syslog.conf设置的处理方法处理收到的消息,默认追加到/va

8、r/log/message中Klogd也可将消息存入一指定文件中,不给syslogd,通过打印调试,若klogd没运行,消息不会送到用户空间,只能查看/proc/kmsg,通过打印调试,开启及关闭消息printk对调试和测试新代码很有帮助,但在正式发布驱动程序时,就需要删除或禁用如何有效地启用/禁用它们?,#undef PDEBUG #ifdef SCULL_DEBUG# ifdef _KERNEL_# define PDEBUG(fmt, args.) printk( KERN_DEBUG scull: fmt, # args)# else # define PDEBUG(fmt, args

9、.) fprintf(stderr, fmt, # args)# endif#else# define PDEBUG(fmt, args.) #endif#undef PDEBUGG#define PDEBUGG(fmt, args.),通过打印调试,打印速度控制Printk有时每秒钟能产生上万条消息充满控制台或使日志文件溢出,若控制台为串口超级终端,过高的消息输出速度会使系统变慢,甚至无法正常响应。内核提供了控制打印速度的函数,原型为: int printk_ratelimit(void);可通过函数的返回值来控制打印输出,若函数返回一个非零值,继续输出消息,否则跳过,例: if (prin

10、tk_ratelimit( ) printk(KERN_NOTICE The printer is still on firen);,通过打印调试,printk_ratelimit跟踪发送到控制台的消息数量,若超过某一阈值,则返回0,否则非0可通过修改下列文件控制printk_ratelimit的行为/proc/sys/kernel/printk_ratelimit/proc/sys/kernel/printk_ratelimit_burst,通过打印调试,打印设备编号当从一个驱动程序打印消息时,有时会希望打印关联的设备编号,内核提供了两个宏:int print_dev_t(char *buf

11、fer, dev_t dev);char *format_dev_t(char *buffer, dev_t dev);,1,3,2,4,第4 章 调试技术,内核中的调试支持,通过打印调试,通过查询调试,通过监视调试,调试系统故障,调试器和相关工具,5,6,通过查询调试,通过打印调试的缺点syslogd会一直保持对其输出文件的同步刷新,降低性能。虽可通过在/etc/syslog.conf中日志文件的名字前加一减号前缀来避免,但调试完后配置会被保留下来虽可通过降低console_loglevel来减少控制台输出,但大量printk的使用也降低性能大多数情况下,获取相关信息的最好方法是在需要的时候

12、才去查询,而不是持续不断地产生数据,如ps、netstat、vmstat等驱动程序开发中可用的查询方法有在/proc中创建文件、ioctl方法、sysfs等,通过查询调试,1. /proc文件系统/proc文件系统是一种读时创建的“内存文件系统”。每个文件都绑定一个内核函数,当文件被读取时,该函数动态地生成文件的“内容”内核使用/proc文件系统向外界导出信息,如/proc/modules因此可通过/proc文件系统将设备信息导出到用户空间,以方便对设备驱动程序进行调试在/proc中实现文件系统需做两件事创建一个函数,用于在文件被读取时生成文件数据创建文件节点,通过查询调试,创建函数当一个进程

13、读取 /proc 文件时, 内核会分配一页内存,我们可以把设备数据写入其中,以返回给用户空间。 那个将数据写入这个缓存区的函数, 就是我们要创建的函数,称为 read_proc 方法,函数原型如下:int (*read_proc)(char *page, char *start, off_t offset, int count, int *eof, void *data);page:指向用来写入数据的缓冲区,大小为一页start:指向数据写入页中的具体位置offset:相对于页边界的偏移量count:写入的字节数eof:指向一个整型数的指针,可返回一个整型数data:提供给驱动程的专用数据指针

14、,通过查询调试,scull中的实现int scull_read_procmem(char *buf, char *start, off_t offset, int count, int *eof, void *data) int i, j, len = 0; int limit = count - 80; for (i = 0; i data; if (down_interruptible(,通过查询调试,创建/proc文件节点原型struct proc_dir_entry *create_proc_read_entry(const char *name, mode_t mode, struc

15、t proc_dir_entry *base, read_proc_t *read_proc, void *data);name:要创建的文件名mode:该文件的保护掩码base:指定该文件所在的目录,若为NULL,则在/proc的根目录read_proc:实现该文件的read_proc方法Scull中的实现create_proc_read_entry(scullmem, 0 , NULL ,scull_read_procmem,NULL );节点删除remove_proc_entry(scullmem, NULL /* parent dir */);,通过查询调试,2. seq_file接口

16、在/proc中创建文件的另一种方式。在/proc下创建的文件大小通常用不超过一页,seq_file接口不受此限制,且相当灵活。seq_file接口假定我们正在创建的虚拟文件要顺序遍历一个项目序列,而这些项目正是必须要返回给用户空间的为使用seq_file,我们必须创建一个简单的“迭代器(iterator)”对象,该对象用来表示项目系列中的位置,每前进一步,该对象输出序列中的一个项目迭代器对象分别为start、next、stop和show,通过查询调试,Start方法首先被调用,原型如下:void *start(struct seq_file *sfile, loff_t *pos);sfile

17、通常被忽略pos表示读取位置,为指向下一个项目的指针。scull 驱动将每个设备作为系列中的一项, 因此pos 可作为 scull_device 数组的索引。于是, scull 使用的 start 方法如下: static void *scull_seq_start(struct seq_file *s, loff_t *pos) if (*pos = scull_nr_devs) return NULL; return scull_devices + *pos;,通过查询调试,next 函数应当将iterator移动到下一个位置, 如果序列里什么都没有剩下就返回 NULL,这个方法的原型是:

18、void *next(struct seq_file *sfile, void *v, loff_t *pos);v 是先前对 start 或者 next 调用所返回的 iterator, pos 是文件的当前位置。next 应当递增 pos 指向的值, scull 的next方法实现如下: static void *scull_seq_next(struct seq_file *s, void *v, loff_t *pos) (*pos)+; if (*pos = scull_nr_devs) return NULL; return scull_devices + *pos;,通过查询调试

19、,当内核处理完 iterator之后, 会调用 stop方法通知我们进行清除工作,stop函数原型如下:void stop(struct seq_file *sfile, void *v);scull 实现没有清理工作要做, 所以它的 stop 方法是空的.在上述调用之间, 内核会调用 show 方法来将实际数据输出到用户空间. 这个方法的原型是:int show(struct seq_file *sfile, void *v);这个方法为 iterator v 指向的项目建立输出。但是,它不能使用 printk, 应该使用针对seq_file的一套特殊函数,通过查询调试,int seq_pr

20、intf(struct seq_file *sfile, const char *fmt, .);这是 seq_file 实现的 printf等价 函数; 它采用常用的格式串和附加值参数. 你必须将给 show 函数的 set_file 结构传递给它Scull中的show方法实现如下:,通过查询调试,static int scull_seq_show(struct seq_file *s, void *v) struct scull_dev *dev = (struct scull_dev *) v; struct scull_qset *d; int i; if (down_interrup

21、tible(,通过查询调试,上面已经定义了完整的迭代器操作函数,scull必须将这些函数打包并和/proc中的某个文件连接起来,首先要填冲一个seq_operations结构体:static struct seq_operations scull_seq_ops = .start = scull_seq_start, .next = scull_seq_next, .stop = scull_seq_stop, .show = scull_seq_show;,通过查询调试,首先创建文件的open方法,该方法将文件连接到seq_file操作static int scull_proc_open(s

22、truct inode *inode, struct file *fil return seq_open(file, ,通过查询调试,对seq_open的调用将file结构和我们上面定义的序列操作连接在一起。事实上, open 是我们必须自己实现的唯一文件操作, 因此我们现在可以建立我们的 file_operations 结构:static struct file_operations scull_proc_ops = .owner = THIS_MODULE, .open = scull_proc_open, .read = seq_read, .llseek = seq_lseek, .r

23、elease = seq_release;,通过查询调试,建立/proc 文件节点函数原型struct proc_dir_entry *create_proc_entry(const char *name,mode_t mode, struct proc_dir_entry *parent);name:要创建的文件名mode:该文件的保护掩码parent:父目录Scull中的实现entry = create_proc_entry(scullseq, 0, NULL);if (entry) entry-proc_fops = ,通过查询调试,ioctl是一个作用于文件描述符上的系统调用, 它接收

24、一个命令号以及(可选地)另一个参数, 常常是一个指针。 作为/proc 文件系统的替代, 你可以实现几个用来调试用的 ioctl 命令,以从驱动程序拷贝相关的数据到用户空间, 在这里你可以检查它们。,1,3,2,4,第4 章 调试技术,内核中的调试支持,通过打印调试,通过查询调试,通过监视调试,调试系统故障,调试器和相关工具,5,6,通过监视调试,通过监视用户空间中应用程序的运行情况,可以捕捉到一些问题有几个方法可以用来监视用户空间程序运行, 你可以运行一个调试器来单步跟踪它的函数, 插入打印语句或者在 strace 下运行程序等等。本节主要讨论strace技术。strace命令功能强,可以显

25、示由用户空间程序所发出的所有系统调用,包括调用参数及用符号表示的返回值strace 有很多命令行选项:-t :显示每个调用发生的时间-T:显示调用所花费的时间 -e:限定被跟踪的调用类型-o:重定向输出到一个文件中, 缺省情况下输出到 stderr.strace 从内核获取信息,这意味着它可以跟踪一个不带有调试支持 (对 gcc是 -g 选项)以及去掉了符号信息的程序。,通过监视调试,例strace ls /dev /dev/scull0open(/dev, O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY) = 3fstat64(3, st_mode=S

26、_IFDIR|0755, st_size=24576, .) = 0fcntl64(3, F_SETFD, FD_CLOEXEC) = 0getdents64(3, /* 141 entries */, 4096) = 4088.getdents64(3, /* 0 entries */, 4096) = 0close(3) = 0.fstat64(1, st_mode=S_IFCHR|0664, st_rdev=makedev(254, 0), .) = 0write(1, MAKEDEVnadmmidi0nadmmidi1nadmmid., 4096) = 4000write(1, bnp

27、tywcnptywdnptywenptywfnptyx0n., 96) = 96write(1, bnptyxcnptyxdnptyxenptyxfnptyy0n., 4096) = 3904write(1, s17nvcs18nvcs19nvcs2nvcs20nvcs21., 192) = 192write(1, nvcs47nvcs48nvcs49nvcs5nvcs50nvc., 673) = 673close(1) = 0exit_group(0) = ?,通过监视调试,例 用wc命令读scull设备.open(/dev/scull0, O_RDONLY|O_LARGEFILE) = 3

28、fstat64(3, st_mode=S_IFCHR|0664, st_rdev=makedev(254, 0), .) = 0read(3, MAKEDEVnadmmidi0nadmmidi1nadmmid., 16384) = 4000read(3, bnptywcnptywdnptywenptywfnptyx0n., 16384) = 4000read(3, s17nvcs18nvcs19nvcs2nvcs20nvcs21., 16384) = 865read(3, , 16384) = 0fstat64(1, st_mode=S_IFCHR|0620, st_rdev=makedev(

29、136, 1), .) = 0write(1, 8865 /dev/scull0n, 17) = 17close(3) = 0exit_group(0) = ?,1,3,2,4,第4 章 调试技术,内核中的调试支持,通过打印调试,通过查询调试,通过监视调试,调试系统故障,调试器和相关工具,5,6,调试系统故障,1. oops消息oops是内核发生错误时(比如引用了一个空指针)所展现给我们的一系列信息,这些信息包含了当时CPU的状态、进程的状态、内核堆栈的状态以及调用栈的记录等大部分系统故障都是引用 NULL 指针或者使用其他不正确指针值引起的,这类故障通常会导致一个 oops 消息.,调试系统

30、故障,例 faulty_write调用由于引用空指针导致的oopsssize_t faulty_write (struct file *filp, const char _user *buf, size_t count, loff_t *pos) *(int *)0 = 0; /*make a simple fault by dereferencing a NULL pointer */ return 0;,调试系统故障,Unable to handle kernel NULL pointer dereference at virtual address 00000000 printing e

31、ip:d083a064Oops: 0002 #1SMPCPU: 0EIP: 0060: Not taintedEFLAGS: 00010246 (2.6.6)EIP is at faulty_write+0x4/0x10 faultyeax: 00000000 ebx: 00000000 ecx: 00000000 edx: 00000000esi: cf8b2460 edi: cf8b2480 ebp: 00000005 esp: c31c5f74ds: 007b es: 007b ss: 0068Process bash (pid: 2086, threadinfo=c31c4000 ta

32、sk=cfa0a6c0)Stack: c0150558 cf8b2460 080e9408 00000005 cf8b2480 00000000 cf8b2460 cf8b2460 fffffff7 080e9408 c31c4000 c0150682 cf8b2460 080e9408 00000005 cf8b2480 00000000 00000001 00000005 c0103f8f 00000001 080e9408 00000005 00000005Call Trace: vfs_write+0xb8/0x130 sys_write+0x42/0x70 syscall_call+

33、0x7/0xbCode: 89 15 00 00 00 00 c3 90 8d 74 26 00 83 ec 0c b8 00 a6 83 d0,说明引发内核错误的原因,说明内核错误的事发现场,说明错误发生时函数调用链,调试系统故障,例 faulty_read 调用由于缓冲区溢出引发的oopsssize_t faulty_read(struct file *filp, char _user *buf, size_t count, loff_t *pos) int ret; char stack_buf4; /* Lets try a buffer overflow */ memset(stac

34、k_buf, 0xff, 20); if (count 4) count = 4; /* copy 4 bytes to the user */ ret = copy_to_user(buf, stack_buf, count); if (!ret) return count; return ret;,调试系统故障,EIP: 0010:Unable to handle kernel paging request at virtual address ffffffff printing eip:ffffffffOops: 0000 #5SMPCPU: 0EIP: 0060: Not tainte

35、dEFLAGS: 00010296 (2.6.6)EIP is at 0xffffffffeax: 0000000c ebx: ffffffff ecx: 00000000 edx: bfffda7cesi: cf434f00 edi: ffffffff ebp: 00002000 esp: c27fff78ds: 007b es: 007b ss: 0068Process head (pid: 2331, threadinfo=c27fe000 task=c3226150)Stack: ffffffff bfffda70 00002000 cf434f20 00000001 00000286

36、 cf434f00 fffffff7 bfffda70 c27fe000 c0150612 cf434f00 bfffda70 00002000 cf434f20 00000000 00000003 00002000 c0103f8f 00000003 bfffda70 00002000 00002000 bfffda70Call Trace: sys_read+0x42/0x70 syscall_call+0x7/0xbCode: Bad EIP value.,调试系统故障,2. 系统挂起内核代码中的大多数错误通常只会导致一个oops消息,但有时也会将系统挂起,系统真挂起时不会再响应任何动作

37、,包括Ctrl-Alt-Del 组合键但有时系统不是真的挂起,只是某种原因使键盘被锁住,此时可用“SySRq魔法键(magic SysRq key)”工具进行调试“ SySRq魔法键” 在大部分体系上都可用。在 PC 上,可通Alt 和SysRq 键组合来激活,在别的平台上可使用其他特殊键(详见 documentation/sysrq.txt)来激活, 在串口控制台上也可用,由第三个键来决定其动作中:r :关闭键盘原始模式。用于当某个崩溃的应用程序( 例如 X 服务器 )让键盘处于一个奇怪状态。k :调用“安全注意键”( SAK ) 功能. SAK 将杀掉在当前控制台的所有运行的进程, 给你一

38、个干净的终端.S:对全部磁盘进行紧急同步.,调试系统故障,u:umount, 尝试以只读模式重新加载所有磁盘。 这个操作常常在 s 之后马上调用, 它可以在系统处于严重故障时节省很多检查文件系统的时间。b:boot,立刻重启系统。 确认要先同步和重新加载磁盘。p :打印处理器寄存器消息。t: 打印当前任务列表。m :打印内存信息。魔法键SysRq 必须在内核配置中显式使能, 大部分的发布版没有使能它, 因为明显的安全理由. 对于用来开发驱动的系统, 使能魔法键SysRq是值得的。魔法键 sysrq 能在运行时关闭, 使用如下命令:echo 0 /proc/sys/kernel/sysrq,1,

39、3,2,4,第4 章 调试技术,内核中的调试支持,通过打印调试,通过查询调试,通过监视调试,调试系统故障,调试器和相关工具,5,6,调试器和相关工具,gdb调试内核gdb /usr/src/linux/vmlinux /proc/kcoreVmlinux:非压缩内核映像文件/proc/kcore:核心文件,对于一个运行的内核,核心文件就是运行时的内核映像gdb可以打印结构体中存放的信息、跟踪一个指针、输出一个变量的值、反汇编一个函数等p jiffiesdisassemble function打印数据时,内核仍在运行,各种数据在不同时间可能会有不同的值,但gdb将第一次读取的数据放在缓存中,第二

40、次读取时得到的仍是原数据执行命令core-file /proc/kcore刷新缓冲区后再读,调试器和相关工具,gdb调试可加载模块上面的命令只可调试内核,但对于可加载模块却无能为力,因为可加载模块并没有随vmlinux传递给gdb,所以gdb 对它一无所知 可加载模块是 ELF 格式的可执行映象, 它们被分成几个代码段. 一个典型的模块可能包含一打或更多段, 以下 3 个段与调试相关:.text:这个段包含了模块的可执行代码.bss /.data :这 2 个段包含了模块的变量. 未初始化的变量在 .bss 中, 已初始化的在 .data 里.要想使 gdb 能够处理可加载模块,必须告诉它模块

41、的段加载在哪里。,调试器和相关工具,每个模块在加载后都会在 /sys/module 目录下产生一个对应的目录,在该目录下又有一个sections目录,sections下有.text、.bss、.data三个文件,文件内容就是3个段的基地址。 例如, 在加载 scull 模块后, /sys/module/scull/sections 会包含一个名为 .text 的文件,文件的内容就是代码段的基地址.通过sysfs获取模块的段地址后,就可以使用如下命令进行调试(gdb) add-symbol-file ./scull.ko 0xd0832000 -s .bss 0xd0837100 -s .dat

42、a 0xd0836be0,调试器和相关工具,例 scull调试(gdb) add-symbol-file scull.ko 0xd0832000 -s .bss 0xd0837100 -s .data 0xd0836be0add symbol table from file scull.ko at .text_addr = 0xd0832000 .bss_addr = 0xd0837100 .data_addr = 0xd0836be0(y or n) yReading symbols from scull.ko.done.(gdb) p scull_devices0$1 = data = 0

43、xcfd66c50, quantum = 4000, qset = 1000, size = 20881, access_key = 0, .,调试器和相关工具,gdb调试内核的局限性不能修改内核数据、不能单步执行、不能设置断点为了让gdb使用内核符号信息,必须打开CONFIG_DEBUG_INFO选项,导致编译的内核庞大,调试器和相关工具,Kdb内核调试器Kdb调试器是一种内嵌式的内核调试器, 作为来自 的一个非官方补丁。 要使用 kdb, 你必须获得这个补丁(确认获得一个匹配你的内核版本的版本), 重建并重安装内核。 kdb 只在IA-32(x86)系统中运行一旦你运行一个内置了kdb的

44、内核, 有几个方法进入调试状态按 Pause(或者 Break) 键启动kdboops 发生时或达到一个断点时也启动kdb。 Kdb启动时, 你看到象这样的一个消息:Entering kdb (0xc0347b80) on processor 0 due to Keyboard Entry0kdbKdb运行时,内核所做的每一件事都会停下来,调试器和相关工具,设置断点0kdb bp scull_readInstruction(i) BP #0 at 0xcd087c5dc (scull_read) is enabled globally adjust 10kdb go观察断点。可在另一台终端用c

45、at命令读scull设备,产生以下信息:Instruction(i) breakpoint #0 at 0xd087c5dc (adjusted)0xd087c5dc scull_read: int3Entering kdb (current=0xcf09f890, pid 1575) on processor 0 due to Breakpoint 0xd087c5dc0kdb,调试器和相关工具,为了查明是如何到达这个位置的,可以查看堆栈跟踪记录:0kdb btESP EIP Function (args)0xcdbddf74 0xd087c5dc scullscull_read0xcdbddf78 0xc0150718 vfs_read+0xb80xcdbddfa4 0xc01509c2 sys_read+0x420xcdbddfc4 0xc0103fcf syscall_call+0x70kdb,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 经营企划

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报