linux驱动调试方法
linux驱动调试方法
声明: 文章的内容来自于韦东山老师的第二期驱动视频中的驱动调试一章。
第一次写博客,写的目的是为了将自己的所学的东西记录下来,防止像以前一样学了就忘了。内容写的乱七八糟,主要是为了以后看的时候有个印象 ,内容可能会有很多错误,欢迎指正。下面就是具体内容:
驱动程序的调试的方法:
打印: printk,自制proc文件
1.1 打印
启动开发板,进入u-boot
print:打印信息,然后设置boot参数
set bootargs noinitrd root=/dev/nfs nfsroot=121.251.65.100:/work/nfs_root/first_fs
ip=121.251.65.103:121.251.65.100:121.251.65.1:255.255.255.0::eth0:off init=/linuxrc console=tty1
最后一个参数的意思是打印在哪儿,tty1表示的是LCD,而ttySAC0表示的是打印在第一串口
1.2 内核
内核中用printk打印,打印时候必然会发送到具体的硬件,所以会调用硬件处理函数,也就是命令行参数bootargs中的console参数
在内核中搜索"console = ", 然后可以找到f:\linux-2.6.22.6\kernel\Printk.c下面的__setup(“console=”, console_setup);
可以大胆的猜测一下,当内核处理参数时, 就会调用console_setup来进行处理。__setup这个函数的作用是一个结构体,这个结构体
里面有一个name等于什么,后面会有一个函数,把这样的结构体放在一起,以后发现了字符串,就会调用相应的函数来处理。
console_setup
add_preferred_console //添加我想用的名为"ttySAC0"控制台,先记录下来
memcpy(c->name, name, sizeof(c->name)); //名字放进字符串,代码很简单,自己可以看看
大胆猜测,硬件操作函数包括LCD打印,串口打印
这个数组是个静态变量,可以直接从这个函数中查看是谁调用了这个数组:
register_console //注册的时候会和console_setup中的name,如果一致的话以后就调用这个函数,当然了这个也是猜测,
接下来看谁调用了register_console,使用默认的规则,带*的表示调用者:
register_console
*s3c24xx_serial_initconsole //f:\linux-2.6.22.6\drivers\serial\S3c2410.c
register_console(&s3c24xx_serial_console);
console s3c24xx_serial_console
.name = S3C24XX_SERIAL_NAME,
.device = uart_console_device,
.flags = CON_PRINTBUFFER,
.index = -1,
.write = s3c24xx_serial_console_write,
.setup = s3c24xx_serial_console_setup1.3. printk
vprintk
/* Emit the output into the temporary buffer */
// 先把输出信息放入临时BUFFER
vscnprintf// Copy the output into log_buf.// 把临时BUFFER里的数据稍作处理,再写入log_buf// 比如printk("abc")会得到"<4>abc", 再写入log_buf// 可以用dmesg命令把log_buf里的数据打印出来重现内核的输出信息// 调用硬件的write函数输出release_console_sem();call_console_drivers(_con_start, _log_end);// 从log_buf得到数据,算出打印级别_call_console_drivers(start_print, cur_index, msg_level); // 如果可以级别够格打印if ((msg_log_level < console_loglevel__call_console_driverscon->write(con, &LOG_BUF(start), end - start);
测试: 利用printk测试第一个程序first_drv,修改以下的代码:
gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
修改为: gpfcon = (volatile unsigned long *)0x56000050;
然后分别编译驱动程序和测试程序, 测试程序的编译方法采用arm-linux-gcc -o firstdrvtest firstdrvtest.c
接下来就是开始进行真正的测试的过程了,首先是:算了直接贴代码,很简单的:
#define DBG_PRINTK printk //定义一个宏定义
//#define DBG_PRINTK(x…) //这个宏定义的目的是为了不需要看见这些乱七八糟的打印的信息可以取消,…是说参数不固定的意思
DBG_PRINTK("%s %s %d\n", FILE, FUNCTION, LINE); //这三个参数的意思是文件名、函数名、所在行
/work/nfs_root/first_fs/first_drv/first_drv.c first_drv_init 71 //这个是实际测试的过程中的打印信息
ps:打印是一个非常好用的工具,要是对内核比较了解的情况下,可以使用打印的功能,对于bug的调试是非常快的
自制工具
根据上节课的总结,printk函数会兵分两路,一个是放在内核的缓冲区中,还有一个是利用硬件打印出来。如果我们想查看哪些信息,可以使用
dmesg将那些信息打印出来
dmesg中的信息是存放在ls -l /proc/kmsg
proc是一个虚拟的文件系统
vi /etc/init.d/rcS
#mount -t proc none /proc
ifconfig eth0 192.168.1.103
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
系统启动的时候会有一个mount -a,这个mount -a是什么意思呢,这个a的意思是all,意思就是把所有的文件系统都挂接上去
那么所有的文件系统是指哪些文件系统呢,是指这些文件:
cat /etc/fstab fstab的意思是file system tab的意思,就是文件系统列表的意思
#device mount-point type options dump fsck order
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
就是把上面定义的文件系统全部都挂接上去,其中proc是虚拟文件系统,挂载在proc目录下面,可以采用下面的语句进行查看:
cat /proc/mounts
rootfs / rootfs rw 0 0
/dev/root / nfs rw,vers=2,rsize=4096,wsize=4096,hard,nolock,proto=udp,timeo=11,retrans=2,sec=sys,addr=192.168.1.100 0 0
proc /proc proc rw 0 0
sysfs /sys sysfs rw 0 0
tmpfs /dev tmpfs rw 0 0
devpts /dev/pts devpts rw 0 0
这是一个虚拟的文件系统,里面的文件是内核帮助我们生成的。
可以将里面的内容读取出来看看, 不用dmesg命令:
cat /proc/kmsg
<3>s3c2440-sdi s3c2440-sdi: CMD[TIMEOUT] #7 op:ALL_SEND_OCR(1) arg:0x00000000 flags:0x0861 retries:0 Status:nothing to complete
<7>mmc0: req done (CMD1): 1/0/0: 00000000 00000000 00000000 00000000
<7>mmc0: clock 0Hz busmode 1 powermode 0 cs 0 Vdd 0 width 0 timing 0
从上面的语句可以看见,前面会带有<>,里面的数字是代表打印级别,打印级别可以修改,修改的方法参考上一课的内容。
然后使用ctrl + c 退出
注意一点,貌似内核只能cat一次,应该是因为指针指到了结尾了,这个是内核自身的原因,不需要深究。接下来就是最终要的配置自己的工具了,可以模仿kmsg,写出一个符合自己需要的my_kmsg, 这个用来打印一些自己需要的信息
可以想象: 要是内核打印的信息非常之多,那么那么多的打印信息很可能会干扰自己的查看,所以如果我们只想看看某个驱动程序的一些打印
内容,我们就可以自己制造一个属于自己的,属于这个驱动程序的my_kmsg来打印驱动程序的一些信息,把它存放一个区域中。方法: 构造proc里面的某个文件,专门用来存放这个驱动程序的打印信息
上面也已经说了,printk的信息一个是存放在log_buf中,另外一个是利用硬件打印出来
其中log_buf中的信息可以通过cat /proc/kmsg来读取出来,其实dmesg其实就是这个读取命令
所以可以这样仿照: 定义一个my_log_buf, 然后再建立/proc/mymsg, 在驱动程序里面写出my_printk, 将my_printk中的信息存放在
my_lon_buf中,然后使用cat /proc/mymsg将驱动的打印信息打印出来。分析kmsg:
e:\linux-2.6.22.6\fs\proc\Proc_misc.c
entry = create_proc_entry(“kmsg”, S_IRUSR, &proc_root); //三个参数, name: kmsg mode:S_IRUSR(只读的意思) parent:proc_root (这个意思是位于proc的根目录下面)
entry->proc_fops = &proc_kmsg_operations;
const struct file_operations proc_kmsg_operations = {
.read = kmsg_read,
.poll = kmsg_poll,
.open = kmsg_open,
.release = kmsg_release,
};
这个解释就是当应用程序打开 cat /proc/kmsg的时候,实际上就是打开了const struct file_operations proc_kmsg_operations这个文件仿照e:\linux-2.6.22.6\fs\proc\Proc_misc.c写一个程序,my_msg.c程序主要是用来打印驱动程序中的信息
App:cat /proc/my_msg 就会进入内核态,发现这是一个虚拟文件系统的文件,就会找到file_operation, 找到里面的read函数
而read函数是干什么呢,当然是copy_to_user,应该就是这么一回事。
static ssize_t kmsg_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
if ((file->f_flags & O_NONBLOCK) && !do_syslog(9, NULL, 0))
return -EAGAIN;
return do_syslog(2, buf, count);
}
这个是内核自带的读函数,判断要是非阻塞方式或者没有数据的情况下就会返回错误,要不然就会执行下面的程序:return do_syslog(2, buf, count);
do_syslog(2, buf, count)
if (!access_ok(VERIFY_WRITE, buf, len)) //看看能否访问
wait_event_interruptible(log_wait,(log_start - log_end)); //等待唤醒,环形缓冲区没有数据的时候就会保持睡眠
插讲一下环形缓冲区: 空: R==W
写:buf[w] = val
w = (w + 1) % 10
读:val = buf[R]
R = (R + 1) % 10
满:(W + 1) % 10 = R
所以当log_start - log_end == 0的时候说明没有数据,这个时候就是休眠的状态后台运行的方式: cat /proc/my_msg &
看看有哪些进程正在运行: ps
杀死进程的方式:在后台运行之后,kill -9 790根据内核打印的错误信息进行分析
下面是一个很简单的例子,可以进行下面的分析:
insmod first_drv.ko
./firstdrvtest
LR is at chrdev_open+0x14c/0x164
LR就是寄存器而已很明显, 出错的地方就是下面这一句话,这句话的一是是从r2寄存器中取出一个值放到r3中,从打印的错误信息中可以看到r2的值是: r2 : 56000050,就是这个指令错误,因为驱动程序需要的是一个映射地址,这个地址是非法的,不能够访问的,所以我们去看看这个地址是在什么地方被初始化,然后就可以看到这个地址没有映射18: e5923000 ldr r3, [r2] //从r2中读取一个值放到r3中去1c: e3c33c3f bic r3, r3, #16128 ; 0x3f00 //清楚某些数值20: e5823000 str r3, [r2]24: e5912000 ldr r2, [r1]28: e5923000 ldr r3, [r2]2c: e3833c15 orr r3, r3, #5376 ; 0x150030: e5823000 str r3, [r2]34: e89da800 ldmia sp, {fp, sp, pc}38: 00000000 andeq r0, r0, r0在实际的工作过程中可能使用的内核并不会提供下面的信息:CPU: 0 Not tainted (2.6.22.6 #1)PC is at first_drv_open+0x18(该指令的偏移值)/0x3c(该函数的总大小) [first_drv]所以我们需要掌握最根本的方法,就是利用PC值找到是哪个驱动程序出了问题
查看输出信息:Unable to handle kernel paging request at virtual address 56000050pgd = c3c78000[56000050] *pgd=00000000Internal error: Oops: 5 [#1]Modules linked in: //内核出错后就不知道是哪个模块了CPU: 0 Not tainted (2.6.22.6 #12)PC is at first_drv_open+0x18/0x3c 这句话有的时候不存在,所以最根本的方法还是看下面的PC值LR is at chrdev_open+0x14c/0x164pc : [<c019cf5c>] lr : [<c008c888>] psr: a0000013sp : c3c77e88 ip : c3c77e98 fp : c3c77e94r10: 00000000 r9 : c3c76000 r8 : c3d3b8e0r7 : 00000000 r6 : 00000000 r5 : c3d52b64 r4 : c04d7240r3 : c019cf44 r2 : 56000050 r1 : c03bb5bc r0 : 00000000Flags: NzCv IRQs on FIQs on Mode SVC_32 Segment userControl: c000717f Table: 33c78000 DAC: 00000015Process firstdrvtest (pid: 749, stack limit = 0xc3c76258)Stack: (0xc3c77e88 to 0xc3c78000)7e80: c3c77ebc c3c77e98 c008c888 c019cf54 00000000 c3d3b8e07ea0: c3d52b64 c008c73c c0467e20 c3d5160c c3c77ee4 c3c77ec0 c0088e48 c008c74c7ec0: c3d3b8e0 c3c77f04 00000003 ffffff9c c002b044 c0024000 c3c77efc c3c77ee87ee0: c0088f64 c0088d58 00000000 00000002 c3c77f68 c3c77f00 c0088fb8 c0088f407f00: c3c77f04 c3d5160c c0467e20 00000000 00000000 c3c79000 00000101 000000017f20: 00000000 c3c76000 c0475748 c0475740 ffffffe8 c0024000 c3c77f68 c3c77f487f40: c008916c c009ec70 00000003 00000000 c3d3b8e0 00000002 bef68edc c3c77f947f60: c3c77f6c c00892f4 c0088f88 00008520 bef68ed4 0000860c 00008670 000000057f80: c002b044 4013365c c3c77fa4 c3c77f98 c00893a8 c00892b0 00000000 c3c77fa87fa0: c002aea0 c0089394 bef68ed4 0000860c 00008720 00000002 bef68edc 000000017fc0: bef68ed4 0000860c 00008670 00000001 00008520 00000000 4013365c bef68ea87fe0: 00000000 bef68e84 0000266c 400c98e0 60000010 00008720 776f677f fdbf0469Backtrace:[<c019cf44>] (first_drv_open+0x0/0x3c) from [<c008c888>] (chrdev_open+0x14c/0x164)[<c008c73c>] (chrdev_open+0x0/0x164) from [<c0088e48>] (__dentry_open+0x100/0x1e8)r8:c3d5160c r7:c0467e20 r6:c008c73c r5:c3d52b64 r4:c3d3b8e0[<c0088d48>] (__dentry_open+0x0/0x1e8) from [<c0088f64>] (nameidata_to_filp+0x34/0x48)[<c0088f30>] (nameidata_to_filp+0x0/0x48) from [<c0088fb8>] (do_filp_open+0x40/0x48)r4:00000002[<c0088f78>] (do_filp_open+0x0/0x48) from [<c00892f4>] (do_sys_open+0x54/0xe4)r5:bef68edc r4:00000002[<c00892a0>] (do_sys_open+0x0/0xe4) from [<c00893a8>] (sys_open+0x24/0x28)[<c0089384>] (sys_open+0x0/0x28) from [<c002aea0>] (ret_fast_syscall+0x0/0x2c)Code: e24cb004 e59f1024 e3a00000 e5912000 (e5923000)然后开始分析上面的输出信息: 最根本的方式是从PC值开始分析,根据PC值确定是内核还是后来加载的驱动的模块假设已经确定是内核的模块导致错误,确定方式如下:3.3.1. pc : [<c019cf5c>]从system.map中查看内核的地址范围: c0004000 ~ c03c6454, 很明显,PC值是在内核的范围内3.3.2. 反汇编内核: arm-linux-objdump -D vmlinux > vmlinux.disvi vmlinux.dis./c019cf5c然后就可以看到下面的信息:425773 c019cf44 <first_drv_open>:425774 c019cf44: e1a0c00d mov ip, sp425775 c019cf48: e92dd800 stmdb sp!, {fp, ip, lr, pc}425776 c019cf4c: e24cb004 sub fp, ip, #4 ; 0x4425777 c019cf50: e59f1024 ldr r1, [pc, #36] ; c019cf7c <.text+0x172f7c>425778 c019cf54: e3a00000 mov r0, #0 ; 0x0425779 c019cf58: e5912000 ldr r2, [r1]425780 c019cf5c: e5923000 ldr r3, [r2] //可以看见依然是这句话出现了问题,具体就不分析了,同上425781 c019cf60: e3c33c3f bic r3, r3, #16128 ; 0x3f00425782 c019cf64: e5823000 str r3, [r2]425783 c019cf68: e5912000 ldr r2, [r1]425784 c019cf6c: e5923000 ldr r3, [r2]425785 c019cf70: e3833c15 orr r3, r3, #5376 ; 0x1500425786 c019cf74: e5823000 str r3, [r2]425787 c019cf78: e89da800 ldmia sp, {fp, sp, pc}425788 c019cf7c: c03bb5bc ldrgth fp, [fp], -ip
3.4.1 确定它属于哪个函数cat /proc/kallsyms > kallsyms.txtcp kallsyms.txt /work/nfs_root/first_fs/ //这句话单纯的目的只是将这个文件放到一个合适的地方,没有什么意思然后在pc(windows)下查看这个文件kallsyms.txt ,可以找到这样的一句话Line 19766: bf000000 t first_drv_open [first_drv]反汇编first_drv.ko : arm-linux-objdump -D first_drv.ko > first_drv.dis6 00000000 <first_drv_open>:7 0: e1a0c00d mov ip, sp8 4: e92dd800 stmdb sp!, {fp, ip, lr, pc}9 8: e24cb004 sub fp, ip, #4 ; 0x410 c: e59f1024 ldr r1, [pc, #36] ; 38 <__mod_vermagic5>11 10: e3a00000 mov r0, #0 ; 0x012 14: e5912000 ldr r2, [r1]13 18: e5923000 ldr r3, [r2]这个是在这个出错的地方14 1c: e3c33c3f bic r3, r3, #16128 ; 0x3f0015 20: e5823000 str r3, [r2]16 24: e5912000 ldr r2, [r1]17 28: e5923000 ldr r3, [r2]18 2c: e3833c15 orr r3, r3, #5376 ; 0x150019 30: e5823000 str r3, [r2]20 34: e89da800 ldmia sp, {fp, sp, pc}21 38: 00000000 andeq r0, r0, r03.4.2 分析回溯(使用打印的寄存器的值分析调用的关系)在反汇编的文件中,高位寄存器(stmdb sp!, {fp, ip, lr, pc})也就是里面靠后的寄存器在分配的空间里占据高位,也就是高地址的位置,在回溯打印信息中他较为靠后,下面是分析的过程:很简单,不行具体详述。Stack: (0xc3e8be88 to 0xc3e8c000)be80: c3e8bebc c3e8be98 c008c888 bf000010 00000000 c04ef820fp ip lr pc r4first_drv_open chrdev_openbea0: c3e7d0a0 c008c73c c0467e20 c3e7b4f4 c3e8bee4 c3e8bec0 c0088e48 c008c74cr5 r6 r7 r8 fp ip lr pcbec0: c04ef820 c3e8bf04 00000003 ffffff9c c002b044 c3e7e000 c3e8befc c3e8bee8r4 r5 r6 r7 r8 sl fp ip__dentry_openbee0: c0088f64 c0088d58 00000000 00000002 c3e8bf68 c3e8bf00 c0088fb8 c0088f40lr pc r4 fp ip lr pc nameidata_to_filpbf00: c3e8bf04 c3e7b4f4 c0467e20 00000000 00000000 c3d35000 00000101 00000001bf20: 00000000 c3e8a000 c04752c8 c04752c0 ffffffe8 c3e7e000 c3e8bf68 c3e8bf48bf40: c008916c c009ec70 00000003 00000000 c04ef820 00000002 be837edc c3e8bf94bf60: c3e8bf6c c00892f4 c0088f88 00008520 be837ed4 0000860c 00008670 00000005bf80: c002b044 4013365c c3e8bfa4 c3e8bf98 c00893a8 c00892b0 00000000 c3e8bfa8bfa0: c002aea0 c0089394 be837ed4 0000860c 00008720 00000002 be837edc 00000001bfc0: be837ed4 0000860c 00008670 00000001 00008520 00000000 4013365c be837ea8bfe0: 00000000 be837e84 0000266c 400c98e0 60000010 00008720 00000000 00000000仅仅分析第一个调用关系,前面已经说了高位寄存器在前,所以错误指令的函数first_drv_open的四个寄存器stmdb sp!, {fp, ip, lr, pc}占据的位置依次是c3e8bebc c3e8be98 c008c888 bf000010,lr = c008c888这个是返回地址,然后反汇编内核,说错了,不是反汇编内核,这个已经确定了是后面的加载模块,好吧,还是反汇编内核因为调用是调用内核中的一些函数,反汇编的方法: arm-linux-objdump -D vmlinux > vmlinux.dis注意两点,中间的 > 千万不要忘了,还有就是只能在linux-2.6.22.6下面反汇编这个文件,因为其他的目录下并没有vmlinuxlr是返回地址,也就是说谁调用了first_drv_open,执行完first_drv_open后就会一个返回地址,从这个返回地址可以看出是谁调用了first_drv_open这份函数,在内核的反汇编文件中vmlinux.dis搜索c008c888, 可以看见这么一段话:138118 c008c73c <chrdev_open>:138119 c008c73c: e1a0c00d mov ip, sp138120 c008c740: e92dd9f0 stmdb sp!, {r4, r5, r6, r7, r8, fp, ip, lr, pc}138121 c008c744: e24cb004 sub fp, ip, #4 ; 0x4138122 c008c748: e24dd004 sub sp, sp, #4 ; 0x4注意这一句话: 138122 c008c748: e24dd004 sub sp, sp, #4 ; 0x4这句话说明栈(sp)实际占据了十个位置,依次在上面对应的位置写出这九个寄存器,其中第一个位置为空。按照这个思路接着搜索: lr = c0088e48, 看见了这么一段话: 134207 c0088d48 <__dentry_open>:134208 c0088d48: e1a0c00d mov ip, sp134209 c0088d4c: e92dddf0 stmdb sp!, {r4, r5, r6, r7, r8, sl, fp, ip, lr, pc}因为lr = c0088f64,在vmlinux.dis中继续搜索c0088f64,得到下面的一段话:134331 c0088f30 <nameidata_to_filp>:134332 c0088f30: e1a0c00d mov ip, sp134333 c0088f34: e92dd810 stmdb sp!, {r4, fp, ip, lr, pc}134334 c0088f38: e24cb004 sub fp, ip, #4 ; 0x4134335 c0088f3c: e24dd004 sub sp, sp, #4 ; 0x4注意这句话134335 c0088f3c: e24dd004 sub sp, sp, #4 ; 0x4后面的就不再详述的,方式都是一样,可以对照回溯信息,会发现按照寄存器分析的调用的关系和回溯信息中的调用关系是完全一样的,但是并不是什么内核都有回溯信息,这个方法是最根本的方法。
修改内核
最后一小节还没有学习,暂时就到这儿了。以后我会总结每次的学习。内容可能会有很多错误,欢迎指正,如果对你有帮助的话,我也佷开心,共同进步
linux驱动调试方法相关推荐
- linux内核串口调试,linux 串口调试方法
linux 串口调试方法 作者:syhdjf 发布于:2015-4-8 16:41 最近项目上用到linux下的串口,与下级模块的通信出了些问题,所以写了个小程序想要测试下串口,物理连接是PC端串口调 ...
- Linux内核调试方法总结
[转]Linux内核调试方法总结 目录[-] 一 调试前的准备 二 内核中的bug 三 内核调试配置选项 1 内核配置 2 调试原子操作 四 引发bug并打印信息 1 BUG()和BUG ...
- Linux驱动调试中的Debugfs的使用简介
Linux驱动调试中的Debugfs的使用简介 (2012-03-31 14:14) 在调试linux驱动的时候,可以用debugfs来调试,debugfs类似字符设备驱动一样,甚至更简单,不需要主设 ...
- Linux驱动调试中的Debugfs的使用简介 CONFIG_DEBUG_FS 的功能与配置
Linux驱动调试中的Debugfs的使用简介 (2012-03-31 14:14) 在调试linux驱动的时候,可以用debugfs来调试,debugfs类似字符设备驱动一样,甚至更简单,不需要主设 ...
- Linux内核调试方法总结【转】
转自:http://my.oschina.net/fgq611/blog/113249 内核开发比用户空间开发更难的一个因素就是内核调试艰难.内核错误往往会导致系统宕机,很难保留出错时的现场.调试内核 ...
- Linux内核调试方法【转】
转自:http://www.cnblogs.com/shineshqw/articles/2359114.html kdb:只能在汇编代码级进行调试: 优点是不需要两台机器进行调试. gdb:在调试模 ...
- linux vc 调试方法,VC实现【API钩取】【调试法】附加调试器
最近在学习逆向核心,在论坛也发了几篇帖子说说自己的经验,帮助自己巩固知识,也方便了大家. 如果帖子中有什么疏漏甚至不对的地方,请大牛们指出,我会积极改正的! 废话不多说,还是我[Miss丿小沫],上教 ...
- linux网卡phy地址修改,【基础技能】Linux PHY驱动调试方法
https://gitee.com/lee790608/linuxPhyDriver STEP1 准备硬件环境 1. 开发环境,可以修改内核代码,编译 2. 硬件开发板,可以进入系统调试,可以传送代码 ...
- linux驱动程序调试方法
驱动程序开发的一个重大难点就是不易调试. 本文目的就是介绍驱动开发中常用的几种直接和间接的调试手段,它们是: 利用printk 查看OOP消息 利用strace 利用内核内置的hacking选项 利用 ...
- linux反调试代码,linux反调试方法
如何防止自己的程序被调试器跟踪,这是一个很有趣的话题,也是反逆向工程中的一个重要话题.这里简单介绍一下Linux平台上的反调试技术. (本文主要参考:http://blog.txipinet.com/ ...
最新文章
- autoware中的交通灯识别(八)
- Linux shell编程与实践(五)之shell程序中循环结构
- 前端书签归纳(持续更新)
- php实现socket
- 深入浅出SQL Server中的死锁
- javascript 自定义类型
- 计算机管理员相关知识,计算机管理员述职报告范文
- ring0和ring3的区别
- windows java配置_菜鸟教程 windows 配置java的环境变量
- “普通人,不要随便创业,安心拿工资过日子比啥都强”你怎么看?
- 80%程序员不知道的职场秘诀,升职加薪不是梦
- hdu2063 二分图的匈牙利匹配
- 2021-06-28获取,更新,删除DOM节点
- QQ音乐JS逆向爬虫,获取调皮的sign参数,我用python全都爬!
- 【axure手机原型】移动应用原型设计新手引导
- 412 Precondition Failed
- STM32 USB HID IAP升级
- 读书笔记--项亮《推荐系统实践》第七章
- 关于Eclipse的使用入门
- OSChina 周一乱弹 —— 论备份容灾的重要性
热门文章
- 【暗恋不可耻但无用】QQ空间爬虫-Java版(jzone-crawler)
- JDownloader 突破百度网盘下载限速
- 有一种爱情,叫沉、重!
- html语言隔开的代码,2、HTML(示例代码)
- java做eda开发_Java学习笔记——EDA事件驱动架构,你掌握了吗
- Lectra力克公司发布新战略 助力客户打造“工业4.0”智造流程
- hexo 炫酷主题配置
- 关于win10激活工具激活系统,浏览器主页被T999,2345劫持解决方法
- c语言实验报告全,c语言实验报告
- EPLAN学习教程目录