Linux内核的Oops

2023-10-30



简介

什么是Oops?从语言学的角度说,Oops应该是一个拟声词。当出了点小事故,或者做了比较尴尬的事之后,你可以说"Oops",翻译成中国话就叫做“哎呦”。“哎呦,对不起,对不起,我真不是故意打碎您的杯子的”。看,Oops就是这个意思。

在Linux内核开发中的Oops是什么呢?其实,它和上面的解释也没什么本质的差别,只不过说话的主角变成了Linux。当某些比较致命的问题出现时,我们的Linux内核也会抱歉的对我们说:“哎呦(Oops),对不起,我把事情搞砸了”。Linux内核在发生kernel panic时会打印出Oops信息,把目前的寄存器状态、堆栈内容、以及完整的Call trace都show给我们看,这样就可以帮助我们定位错误。

Oops示例

下面,我们来看一个实例。为了突出本文的主角--Oops,这个例子唯一的作用就是造一个空指针引用错误。

#include <linux/kernel.h>
#include <linux/module.h>
 
static int __init hello_init(void)
{
    int *p = 0;
     
    *p = 1; 
    return 0;
}
 
static void __exit hello_exit(void)
{
    return;
}
 
module_init(hello_init);
module_exit(hello_exit);
 
MODULE_LICENSE("GPL");


很明显,错误的地方就是第8行。

接下来,我们把这个模块编译出来,再用insmod来插入到内核空间,正如我们预期的那样,Oops出现了。


[  100.243737] BUG: unable to handle kernel NULL pointer dereference at (null)
[  100.244985] IP: [<f82d2005>] hello_init+0x5/0x11 [hello]
[  100.262266] *pde = 00000000 
[  100.288395] Oops: 0002 [#1] SMP 
[  100.305468] last sysfs file: /sys/devices/virtual/sound/timer/uevent
[  100.325955] Modules linked in: hello(+) vmblock vsock vmmemctl vmhgfs acpiphp snd_ens1371 gameport snd_ac97_codec ac97_bus snd_pcm_oss snd_mixer_oss snd_pcm snd_seq_dummy snd_seq_oss snd_seq_midi snd_rawmidi snd_seq_midi_event snd_seq snd_timer snd_seq_device ppdev psmouse serio_raw fbcon tileblit font bitblit softcursor snd parport_pc soundcore snd_page_alloc vmci i2c_piix4 vga16fb vgastate intel_agp agpgart shpchp lp parport floppy pcnet32 mii mptspi mptscsih mptbase scsi_transport_spi vmxnet
[  100.472178] [  100.494931] Pid: 1586, comm: insmod Not tainted (2.6.32-21-generic #32-Ubuntu) VMware Virtual Platform
[  100.540018] EIP: 0060:[<f82d2005>] EFLAGS: 00010246 CPU: 0
[  100.562844] EIP is at hello_init+0x5/0x11 [hello]
[  100.584351] EAX: 00000000 EBX: fffffffc ECX: f82cf040 EDX: 00000001
[  100.609358] ESI: f82cf040 EDI: 00000000 EBP: f1b9ff5c ESP: f1b9ff5c
[  100.631467]  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
[  100.657664] Process insmod (pid: 1586, ti=f1b9e000 task=f137b340 task.ti=f1b9e000)
[  100.706083] Stack:
[  100.731783]  f1b9ff88 c0101131 f82cf040 c076d240 fffffffc f82cf040 0072cff4 f82d2000
[  100.759324] <0> fffffffc f82cf040 0072cff4 f1b9ffac c0182340 f19638f8 f137b340 f19638c0
[  100.811396] <0> 00000004 09cc9018 09cc9018 00020000 f1b9e000 c01033ec 09cc9018 00015324
[  100.891922] Call Trace:
[  100.916257]  [<c0101131>] ? do_one_initcall+0x31/0x190
[  100.943670]  [<f82d2000>] ? hello_init+0x0/0x11 [hello]
[  100.970905]  [<c0182340>] ? sys_init_module+0xb0/0x210
[  100.995542]  [<c01033ec>] ? syscall_call+0x7/0xb
[  101.024087] Code: <c7> 05 00 00 00 00 01 00 00 00 5d c3 00 00 00 00 00 00 00 00 00 00 
[  101.079592] EIP: [<f82d2005>] hello_init+0x5/0x11 [hello] SS:ESP 0068:f1b9ff5c
[  101.134682] CR2: 0000000000000000
[  101.158929] ---[ end trace e294b69a66d752cb ]---

Oops首先描述了这是一个什么样的bug,然后指出了发生bug的位置,即“IP: [<f82d2005>] hello_init+0x5/0x11 [hello]”和EIP is at hello_init+0x5/0x11 [hello](有些是PC指向这个地址)。这里告诉我们,hello_init函数有0x11这么大,而Oops发生在0x5处。

使用objdump反编译定位出错代码

在这里,我们需要用到一个辅助工具objdump来帮助分析问题。objdump可以用来反汇编,命令格式如下:

objdump -S  hello.o

下面是hello.o反汇编的结果,而且是和C代码混排的,非常的直观。

hello.o:     file format elf32-i386
 
 
Disassembly of section .init.text:
 
00000000 <init_module>:
#include <linux/kernel.h>
#include <linux/module.h>
 
static int __init hello_init(void)
{
   0:   55                      push   %ebp
    int *p = 0;
     
    *p = 1;
     
    return 0;
}
   1:   31 c0                   xor    %eax,%eax
#include <linux/kernel.h>
#include <linux/module.h>
 
static int __init hello_init(void)
{
   3:   89 e5                   mov    %esp,%ebp
    int *p = 0;
     
    *p = 1;
   5:   c7 05 00 00 00 00 01    movl   $0x1,0x0
   c:   00 00 00 
     
    return 0;
}
   f:   5d                      pop    %ebp
  10:   c3                      ret    
 
Disassembly of section .exit.text:
 
00000000 <cleanup_module>:
 
static void __exit hello_exit(void)
{
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   e8 fc ff ff ff          call   4 <cleanup_module+0x4>
    return;
}
   8:   5d                      pop    %ebp
   9:   c3                      ret    

对照Oops的提示,我们可以很清楚的看到,出错的位置hello_init+0x5的汇编代码是:

5:c7 05 00 00 00 00 01 movl   $0x1,0x0

这句代码的作用是把数值1存入0这个地址,这个操作当然是非法的。

我们还能看到它对应的c代码是:

*p = 1;

Bingo!在Oops的帮助下我们很快就解决了问题。

我们再回过头来检查一下上面的Oops,看看Linux内核还有没有给我们留下其他的有用信息。

Oops: 0002 [#1]

这里面,0002表示Oops的错误代码(写错误,发生在内核空间),#1表示这个错误发生一次。

本文的这个例子非常简单,Oops发生以后没有造成宕机,这样我们就可以从dmesg中查看到完整的信息。但更多的情况是Oops发生的同时系统也会宕机,此时这些出错信息是来不及存入文件中的,关掉电源后就无法再看到了。我们只能通过其他的方式来记录:手抄或者拍照。

还有更坏的情况,如果Oops信息过多的话,一页屏幕显示不全,我们怎么来查看完整的内容呢?第一种方法,在grub里用vga参数指定更高的分辨率以使屏幕可以显示更多的内容。很明显,这个方法其实解决不了太多的问题;第二种方法,使用两台机器,把调试机的Oops信息通过串口打印到宿主机的屏幕上。但现在大部分的笔记本电脑是没有串口的,这个解决方法也有很大的局限性;第三种方法,使用内核转储工具kdump把发生Oops时的内存和CPU寄存器的内容dump到一个文件里,之后我们再用gdb来分析问题。

 

开发内核驱动的过程中可能遇到的问题是千奇百怪的,调试的方法也是多种多样,Oops是Linux内核给我们的提示,我们要用好它。

gdb定位出错代码

来自Linus Torvalds的讨论:
https://groups.google.com/group/ ... 41/ed9c0a0cfcd31111
例如这样的一个Oops:
Oops: 0000 [#1] PREEMPT SMP 
Modules linked in: capidrv kernelcapi isdn slhc ipv6 loop dm_multipath snd_ens1371 gameport snd_rawmidi snd_ac97_codec ac97_bus s nd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd parport_pc floppy parport pcnet32 soundcore mii pcspkr snd_page_alloc ac i2c_piix4 i2c_core button power_supply sr_mod sg cdrom ata_piix libata dm_snapshot dm_zero dm_mirror dm_mod BusLogic sd_mod scsi_mod ext3 jbd mbcache uhci_hcd ohci_hcd ehci_hcd
Pid: 1726, comm: kstopmachine Not tainted (2.6.24-rc3-module #2)
EIP: 0060:[] EFLAGS: 00010092 CPU: 0
EIP is at list_del+0xa/0x61
EAX: e0c3cc04 EBX: 00000020 ECX: 0000000e EDX: dec62000
ESI: df6e8f08 EDI: 000006bf EBP: dec62fb4 ESP: dec62fa4
DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 
Process kstopmachine (pid: 1726, ti=dec62000 task=df8d2d40 task.ti=dec62000)
Stack: 000006bf dec62fb4 c04276c7 00000020 dec62fbc c044ab4c dec62fd0 c045336c 
df6e8f08 c04532b4 00000000 dec62fe0 c043deb0 c043de75 00000000 00000000 
c0405cdf df6e8eb4 00000000 00000000 00000000 00000000 00000000 
Call Trace:
[] show_trace_log_lvl+0x1a/0x2f
[] show_stack_log_lvl+0x9b/0xa3
[] show_registers+0xa3/0x1df
[] die+0x11f/0x200
[] do_page_fault+0x533/0x61a
[] error_code+0x72/0x78
[] __unlink_module+0xb/0xf
[] do_stop+0xb8/0x108
[] kthread+0x3b/0x63
[] kernel_thread_helper+0x7/0x10
=======================
Code: 6b c0 e8 2e 7e f6 ff e8 d1 16 f2 ff b8 01 00 00 00 e8 aa 1c f4 ff 89 d8 83 c4 10 5b 5d c3 90 90 90 55 89 e5 53 83 ec 0c 8b 48 04 11 39 c2 74 18 89 54 24 08 89 44 24 04 c7 04 24 be 32 6b c0 
EIP: [] list_del+0xa/0x61 SS:ESP 0068:dec62fa4
note: kstopmachine[1726] exited with preempt_count 1

1, 有自己编译的vmlinux: 使用gdb

编译时打开complie with debug info选项。 
注意这行: 
EIP is at list_del+0xa/0x61
这告诉我们,list_del函数有0x61这么大,而Oops发生在0xa处。 

那么我们先看一下list_del从哪里开始: 
# grep list_del /boot/System.map-2.6.24-rc3-module
c10e5234 T plist_del
c10e53cc T list_del
c120feb6 T klist_del
c12d6d34 r __ksymtab_list_del
c12dadfc r __ksymtab_klist_del
c12e1abd r __kstrtab_list_del
c12e9d03 r __kstrtab_klist_del
于是我们知道,发生Oops时的EIP值是:
c10e53cc + 0xa == c10e53d6
然后用gdb查看:
# gdb /home/arc/build/linux-2.6/vmlinux
(gdb) b *0xc10e53d6
Breakpoint 1 at 0xc10e53d6: file /usr/src/linux-2.6.24-rc3/lib/list_debug.c, line 64.
看,gdb直接就告诉你在哪个文件、哪一行了。
gdb中还可以这样:
# gdb Sources/linux-2.6.24/vmlinux
(gdb) l *do_fork+0x1f
0xc102b7ac is in do_fork (kernel/fork.c:1385).
1380
1381 static int fork_traceflag(unsigned clone_flags)
1382 {
1383 if (clone_flags & CLONE_UNTRACED)
1384 return 0;
1385 else if (clone_flags & CLONE_VFORK) {
1386 if (current->ptrace & PT_TRACE_VFORK)
1387 return PTRACE_EVENT_VFORK;
1388 } else if ((clone_flags & CSIGNAL) != SIGCHLD) {
1389 if (current->ptrace & PT_TRACE_CLONE)
(gdb)
也可以直接知道line number。
或者:
(gdb) l *(0xffffffff8023eaf0 + 0xff) /* 出错函数的地址加上偏移 */

2, 没有自己编译的vmlinux: TIPS

如果在lkml或bugzilla上看到一个Oops,而自己不能重现,那就只能反汇编以"Code:"开始的行。 这样可以尝试定位到 源代码中。
注意,Oops中的Code:行,会把导致Oops的第一条指令,也就是EIP的值的第一个字节, 用尖括号括起来。 但是,有些 体系结构(例如常见的x86)指令是不等长的(不一样的指令可能有不一样的长度),所以要不断的尝试(trial-and-error)。
Linus通常使用一个小程序,类似这样:


const char array[] = "\xnn\xnn\xnn...";
int main(int argc, char *argv[])
{
printf("%p\n", array);
*(int *)0 = 0;
}


e.g. /*{{{*/ /* 注意, array一共有从array[0]到array[64]这65个元素, 其中出错的那个操作码 == arry[43] */

#include 
#include 
const char array[] ="\x6b\xc0\xe8\x2e\x7e\xf6\xff\xe8\xd1\x16\xf2\xff\xb8

\x01\x00\x00\x00\xe8\xaa\x1c\xf4\xff\x89\xd8\x83\xc4\x10\x5b\x5d\xc3\x90\x90

\x90\x55\x89\xe5\x53\x83\xec\x0c\x8b\x48\x04\x8b\x11\x39\xc2\x74\x18\x89

\x54\x24\x08\x89\x44\x24\x04\xc7\x04\x24\xbe\x32\x6b\xc0";
int main(int argc, char *argv[])
{
printf("%p\n", array);
*(int *)0 = 0;
}
/*}}}*/


用gcc -g编译,在gdb里运行它:
[arc@dhcp-cbjs05-218-251 ~]$ gdb hello
GNU gdb Fedora (6.8-1.fc9)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu"...
(no debugging symbols found)
(gdb) r
Starting program: /home/arc/hello
0x80484e0
Program received signal SIGSEGV, Segmentation fault.
注意,这时候就可以反汇编0x80484e0这个地址:
(gdb) disassemble 0x80484e0
Dump of assembler code for function array:
0x080484e0 : imul $0xffffffe8,%eax,%eax
0x080484e3 : jle,pn 0x80484dc 
0x080484e6 : ljmp *
0x080484e8 : rcll (%esi)
0x080484ea : repnz (bad)
0x080484ec : mov $0x1,%eax
0x080484f1 : call 0x7f8a1a0
0x080484f6 : mov %ebx,%eax
0x080484f8 : add $0x10,%esp
0x080484fb : pop %ebx
0x080484fc : pop %ebp
0x080484fd : ret
0x080484fe : nop
0x080484ff : nop
0x08048500 : nop
0x08048501 : push %ebp
0x08048502 : mov %esp,%ebp
0x08048504 : push %ebx
0x08048505 : sub $0xc,%esp
0x08048508 : mov 0x4(%eax),%ecx
0x0804850b : mov (%ecx),%edx
0x0804850d : cmp %eax,%edx
0x0804850f : je 0x8048529
0x08048511 : mov %edx,0x8(%esp)
0x08048515 : mov %eax,0x4(%esp)
0x08048519 : movl $0xc06b32be,(%esp)
0x08048520 : add %ah,0xa70
End of assembler dump.
(gdb)
OK, 现在你知道出错的那条指令是array[43],也就是mov (%ecx),%edx,也就是说,(%ecx)指向了一个错误内存地址。
补充:
为了使汇编代码和C代码更好的对应起来, Linux内核的Kbuild子系统提供了这样一个功能: 任何一个C文件都可以单独编译成汇编文件,例如:
make path/to/the/sourcefile.s
例如我想把kernel/sched.c编译成汇编,那么:
make kernel/sched.s V=1
或者:
make kernel/sched.lst V=1
编译出*.s文件

有时侯需要对*.s文件进行分析,以确定BUG所在的位置。 对任何一个内核build目录下的*.c文件,都可以
直接编译出*.s文件。
# make drivers/net/e100.s V=1

而对于自己写的module,就需要在Makefile中有一个灵活的target写法:

# cat Makefile
obj-m := usb-skel.o
KDIR := /lib/modules/`uname -r`/build
traget := modules
default:
make -C $(KDIR) M=$(shell pwd) $(target)
clean:
rm -f *.o *.ko .*.cmd *.symvers *.mod.c
rm -rf .tmp_versions
# make target=usb-skel.s V=1

这样,kbuild系统才知道你要make的目标不是modules,而是usb-skel.s。
另外, 内核源代码目录的./scripts/decodecode文件是用来解码Oops的:
./scripts/decodecode

Oops error code

Oops的错误代码根据错误的原因会有不同的定义,本文中的例子可以参考下面的定义(如果发现自己遇到的Oops和下面无法对应的话,最好去内核代码里查找):

 * error_code:
 *      bit 0 == 0 means no page found, 1 means protection fault
 *      bit 1 == 0 means read, 1 means write
 *      bit 2 == 0 means kernel, 1 means user-mode
 *      bit 3 == 0 means data, 1 means instruction

有时候,Oops还会打印出Tainted信息。这个信息用来指出内核是因何种原因被tainted(直译为“玷污”)。具体的定义如下:

1: 'G' if all modules loaded have a GPL or compatible license, 'P' if any proprietary module has been loaded.  Modules without a MODULE_LICENSE or with a MODULE_LICENSE that is not recognised by insmod as GPL compatible are assumed to be proprietary.
  2: 'F' if any module was force loaded by "insmod -f", ' ' if all modules were loaded normally.
  3: 'S' if the oops occurred on an SMP kernel running on hardware that hasn't been certified as safe to run multiprocessor. Currently this occurs only on various Athlons that are not SMP capable.
  4: 'R' if a module was force unloaded by "rmmod -f", ' ' if all modules were unloaded normally.
  5: 'M' if any processor has reported a Machine Check Exception, ' ' if no Machine Check Exceptions have occurred.
  6: 'B' if a page-release function has found a bad page reference or some unexpected page flags.
  7: 'U' if a user or user application specifically requested that the Tainted flag be set, ' ' otherwise.
  8: 'D' if the kernel has died recently, i.e. there was an OOPS or BUG.
  9: 'A' if the ACPI table has been overridden.
 10: 'W' if a warning has previously been issued by the kernel. (Though some warnings may set more specific taint flags.)
 11: 'C' if a staging driver has been loaded.
 12: 'I' if the kernel is working around a severe bug in the platform firmware (BIOS or similar).

基本上,这个Tainted信息是留给内核开发者看的。用户在使用Linux的过程中如果遇到Oops,可以把Oops的内容发送给内核开发者去debug,内核开发者根据这个Tainted信息大概可以判断出kernel panic时内核运行的环境。如果我们只是debug自己的驱动,这个信息就没什么意义了。


http://www.cnblogs.com/wwang/archive/2010/11/14/1876735.html

http://bbs.chinaunix.net/thread-3672391-1-1.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux内核的Oops 的相关文章

  • KVM内核代码结构

    KVM内核代码结构 因为KVM的源代码已经包含在了Linux的内核树中 因此我们只需直接从www kernel org下载代码即可 内核源码包打开较大 解开后目录结构大概是这个样子 涉及KVM的主要有两个目录 virt和arch x86 k
  • linux内核开发基础(linux内核源码、树莓派源码编译、SD卡挂载)

    首先下载树莓派linux内核源码 下载网址 https github com raspberrypi linux 在树莓派使用指令 uname r查看当前树莓派的版本号 然后选择对应的linux内核版本号进行下载 将linux内核源码从共享
  • 十九、Linux驱动之虚拟网卡驱动

    1 基本概念 网络设备是完成用户数据包在网络媒介上发送和接收的设备 它将上层协议传递下来的数据包以特定的媒介访问控制方式进行发送 并将接收到的数据包传递给上层协议 与字符设备和块设备不同 网络设备并不对应于 dev目录下的文件 应用程序最终
  • linux-arm电源管理

    一文搞懂ARM SoC功耗控制架构
  • linux支持usb打印机

    配置CONFIG USB PRINTER y inux内核默认运行打印机 核 驱动 直接在配置上CONFIG USB PRINTER y添加上去就好了 make menuconfig 选上USB打印机选项 Device Drivers gt
  • 第三章 套接字相关数据结构--基于Linux3.10

    本章是对socket通信过程中使用到的比较重要的据结构罗列和意义的阐述 在阅读其它层的代码前 先来看几个重要的数据结构 这几个数据结构贯串四层模型 3 1 socket对应的内核结构体 在用户空间使用socket 函数创建一个套接字 对应的
  • Linux驱动-编译驱动模块的Makefile和脚本

    Makefile内容 ARCH arm CROSS COMPILE arm poky linux gnueabi 也可以同时编译多个模块 obj m export symbol o export symbol1 o export symbo
  • UBOOT命令总结(转)

    UBOOT命令总结 转 很好的UBOOT命令总结 我在起步时就是看的这篇东西 熟悉了以后就用 看自带帮助就行 Printenv 打印环境变量 Uboot gt printenvbaudrate 115200ipaddr 192 168 1
  • file_operations 结构体

    file operations 结构体中的成员函数是字符设备驱动程序设计的主体内容 这些函数实际会在应用程序进行 Linux 的 open write read close 等系统调用时最终被调用 file operations 结构体目前
  • 构建Buildroot根文件系统(I.MX6ULL)

    Busybox构建的根文件系统只有一些常用的命令和文件 Buildroot不仅集成了 busybox 而且还集成了各种常见的第三方库和软件 开发环境 Buildroot 版本 buildroot 2019 02 6 tar gz 虚拟机 4
  • Fedora12 Linux启动过程

    1 加载BIOS BIOS Basic Input Output System 是固化到计算机内主板上一个ROM芯片上的程序 保存CPU相关信息 设备启动顺序信息 硬盘信息 内存信息等等 打开计算机电源第一项工作即加载BIOS 进行POST
  • 【内核驱动】Linux概述

    00 目录 文章目录 00 目录 01 Unix简介 02 Linux简介 03 Linux发展史 04 单内核与微内核区别 05 Linux内核 06 Linux内核组成 07 Linux官方网站 08 附录 01 Unix简介 UNIX
  • linux内核对于指令异常的处理

    1 处理流程 以arm64来介绍一下流程 如果在用户层发生指令异常时 首先进入入口el0 undef arch arm64 kernel entry s el0 undef Undefined instruction enable inte
  • 【xenclient】 使用小结 -- ubuntu的千百bug

    说道多系统 不能不提下ubuntu 以前redhat似乎是linux的领头羊 但在桌面领域 跟windows还是差得太远 在linux最弱的桌面特性上 ubuntu算是第一个以桌面特效全面超越windows的系统了 因此我的系统 除了保留做
  • 关于/dev/console的个人理解

    嵌入式开发里 首先需要配置一个串口 用于打印printk信息到控制台 以2440为例 这里的 dev console 设备号 5 1 就是控制台 用于printk信息输出到的设备 但是呢 dev console是个虚拟设备 他需要映射到真正
  • linux设备驱动makefile入门解析

    以下内容仅作参考 能力有限 如有错误还请纠正 对于一个普通的linux设备驱动模块 以下是一个经典的makefile代码 使用下面这个makefile可以 完成大部分驱动的编译 使用时只需要修改一下要编译生成的驱动名称即可 只需修改obj
  • int $0x80系统调用的idea

    1 基础知识 用户态和内核态 一般现代CPU都有几种不同的指令执行级别 Linux总共划分为4个指令执行级别 内核运行在0级别上 1 2级别默认不运行 用户程序运行在3级别上 在内核指令执行级别上 代码可以执行特权指令 访问任意的物理地址
  • 最全的交叉编译Makefile讲解

    最近正在搞交叉编译 参考很多博客 学习了一下Makefile的编写 记录一下Makefile内代码是什么意思 代码如下 简单的hello ko的makefile ifneq KERNELRELEASE obj m hello o else
  • linux内核-软中断与Bottom Half

    中断服务一般都是在将中断请求关闭的条件下执行的 以避免嵌套而使控制复杂化 可是 如果关中断的时间持续太长就可能因为CPU不能及时响应其他的中断请求而使中断 请求 丢失 为此 内核允许在将具体的中断服务程序挂入中断请求队列时将SA INTER
  • linux内核学习(7)粗略走走kbuild Makefile编译流程

    今天看Makefile文件 我头大了 此Makefile非彼Makefile 里面多了很多内置命令 比如origin patsubst等等啦 这些都没听说过 更可恶的是 连网上都没有 可见 这是一件多么伤人的事情 分析这样的 真是让人折寿啊

随机推荐

  • monaco-editor基本使用以及monaco-editor封装成vue组件

    文章目录 一 monaco editor基本使用 二 monaco editor封装成vue组件 一 monaco editor基本使用 以vue2项目为例 安装依赖 npm i monaco editor npm i monaco edi
  • Redis知识总结

    Redis的全称是 Remote Dictionary Server Redis是一个开源 BSD许可 内存数据结构存储 可以用作数据库 缓存和消息代理 它支持数据结构 如字符串 散列 列表 集合 带有范围查询的排序集 位图 超级日志 具有
  • unity3D 鼠标滚轮实现物体的大小缩放

    这个实现的方法不难 难的可能是要弄懂鼠标滚轮响应函数的机制 响应函数是Input GetAxis Mouse ScrollWheel 其中 这个函数是有返回值的 类型是float 向前滚是返回正数 向后滚是返回负数 所以 下面这个脚本操作的
  • 域名系统和 DNS

    目录 1 名字解析介绍和DNS 1 2 DNS服务工作原理 1 3 DNS查询类型 1 4 名称服务器 1 5 解析类型 1 6 完整的查询请求经过的流程 2 DNS 服务相关概念和技术 2 1 DNS服务器的类型 2 1 1 主DNS服务
  • 人工智能知识全面讲解:机器学习的过程

    1 3 1 机器学习的三个阶段 学习了机器学习的概念后 我们知道机器学习实际上就是计算机通过算法 处理数据并且学得模型的过程 模型 这个词经常被我们挂在嘴边 但大部 分人仍然不清楚模型是怎么做出来的 模型在计算机里是怎么表示的 对模型 很难
  • linux中的无人职守安装脚本kickstart

    一 kickstart自动安装脚本的作用 在企业中安装多台操作系统时面临的问题 当安装Linux操作系统时 安装过程会需要回答很多关于设定的问题 这些问题必须手动选择 否则无法进行安装 当只安装1台Linux系统 手动选择设定工作量比较轻松
  • 使用Go语言实现百度网盘样的云存储系统

    目录 1 项目概述 2 开始项目 3 用户服务 4 文件服务 5 结语 欢迎来到这篇关于使用Go语言实现云存储系统的博客 在这篇博客中 我们将讨论如何使用Go语言和一些常见的开源库 实现一个简单的云存储系统 这个系统将包含用户注册 登录 上
  • m1 mac 使用 obs + BlackHole 内录电脑音频

    直接 obs 是内录不了的 由于 macOS 的限制 无法获取桌面音频 于是使用 BlackHole Github 工具 该方案的原理是将电脑音频同时输出到你的设备 耳机 扬声器等 BlackHole 然后让 OBS 获取 BlackHol
  • Lambda表达式【C++语法】

    C L a m b d a
  • 测试驱动开发(TDD)实践与技巧

    文章目录 引言 Google Mock 测试用例结构 断言 经典式断言 Hamcrest 断言 测试驱动开发 第一个示例 开场白 开始吧 去掉不干净的代码 增量性 fixture 设置 思索与测试驱动开发 测试驱动与测试 测试驱动开发基础与
  • Android app多渠道打包的流程与源代码示例

    Android app多渠道打包的流程与源代码示例 多渠道打包是指通过一次构建过程生成适用于不同应用商店 市场或渠道的多个APK文件 这样可以方便开发者将应用同时发布到多个平台上 提高应用的覆盖率和下载量 本文将介绍实现多渠道打包的步骤 并
  • 静态路由实验(思科Cisco)

    思科静态配置命令 静态路由的配置命令如下 router config ip route 目的网络 网络掩码 下一跳地址 出接口 默认路由的配置命令如下 router config ip route 0 0 0 0 0 0 0 0 下一跳地址
  • kali linux之手动漏洞挖掘三(sql注入)

    服务器端程序将用户输入作为参数作为查询条件 直接拼写sql语句 并将结果返回给客户端浏览器 如判断登录 select from users where user uname and password pass select from use
  • 看完这篇 教你玩转渗透测试靶机vulnhub——DC7

    Vulnhub靶机DC7渗透测试详解 Vulnhub靶机介绍 Vulnhub靶机下载 Vulnhub靶机安装 Vulnhub靶机漏洞详解 信息收集 SSH登入 漏洞发现与利用 提权 获取flag Vulnhub靶机渗透总结 Vulnhub靶
  • 使用C#编写程序屏蔽键盘输入

    使用C 编写程序屏蔽键盘输入 在C 中 我们可以使用System Windows Forms命名空间下的Keyboard类来实现屏蔽键盘输入的功能 下面是一段示例代码 演示了如何屏蔽键盘输入 using System using Syste
  • Java自学视频整理

    1 Java基础视频 张孝祥JAVA视频教程 完整版 RMVB 东西网 历经5年锤炼 史上最适合初学者入门的Java基础视频 传智播客 张孝祥2010年贺岁视频 Java高新技术 传智播客 Java多线程与并发库高级应用 传智播客 尚学堂J
  • 区块链自定义节点

    本地自定义节点 1 cmd中 安装好geth后 cmd geth help 检查是否geth是否安装好 然后输入命令geth datadir testNet dev rpc console 自定义本地的节点 2 metaMask 再在met
  • SOCKET套接字

    操作系统提供 用于开发网络应用的一系列API函数接口 可以称为套接字函数 所有的系统平台都有对SOCKET套接字的兼容和实现 虽然网络环境中有大量的协议类型 但是绝大多数协议都是采用TCP和UDP 也就是说很多软件或网站的访问与链接一样使用
  • Java+SSM+Vue 毕业设计 汽车租赁系统(含源码+论文)

    文章目录 1 项目简介 2 实现效果 2 1 界面展示 3 设计方案 3 1 概述 3 2 系统流程 3 3 系统结构设计 4 项目获取 1 项目简介 Hi 各位同学好呀 这里是M学姐 今天向大家分享一个今年 2022 最新完成的毕业设计项
  • Linux内核的Oops

    简介 什么是Oops 从语言学的角度说 Oops应该是一个拟声词 当出了点小事故 或者做了比较尴尬的事之后 你可以说 Oops 翻译成中国话就叫做 哎呦 哎呦 对不起 对不起 我真不是故意打碎您的杯子的 看 Oops就是这个意思 在Linu