Footprint

Footprint

ELF文件格式

ELF文件格式

参考:

  1. https://blog.csdn.net/wxh0000mm/article/details/127635576
  2. https://blog.csdn.net/GrayOnDream/article/details/124564129

1. 前言

在嵌入式开发中,我们编写的程序最终会被编译成一个可执行的文件,这个文件可被系统加载执行。
能被加载执行,说明这个可行执行文件具备统一的符合规范的文件。那么它的格式是啥呢?
ARM 系统基本文件格式有三种 :

  1. BIN,平板式二进制格式 , 一般用于直接烧写到Flash 中,也可以用于加载到monitor程序中 。
  2. ELF,EXECUTABLE AND LINKABLE FORMAT, 一种通用的 OBJECT文件格式 , 一般由 GNIJ COMPILER COLLECTION (GCC)产生 。
  3. AXF,BIN格式的扩展版 , 主体部分同BIN , 在文件头和尾加入了调试用的信息 。

现在的编译器基本上都是gcc了,所以重点学习ELF文件格式。

ELF的英文全称是The Executable and Linking Format,最初是由UNIX系统实验室开发、发布的ABI(Application Binary Interface)接口的一部分,也是Linux的主要可执行文件格式。

从使用上来说,主要的ELF文件的种类主要有三类:

  • 可执行文件(.out):Executable File,包含代码和数据,是可以直接运行的程序。其代码和数据都有固定的地址 (或相对于基地址的偏移 ),系统可根据这些地址信息把程序加载到内存执行。
  • 可重定位文件(.o文件):Relocatable File,包含基础代码和数据,但它的代码及数据都没有指定绝对地址,因此它适合于与其他目标文件链接来创建可执行文件或者共享目标文件。
  • 共享目标文件(.so):Shared Object File,也称动态库文件,包含了代码和数据,这些数据是在链接时被链接器(ld)和运行时动态链接器(ld.so.l、libc.so.l、ld-linux.so.l)使用的。

2. ELF文件格式

在编译过程中ELF文件格式在链接和程序的运行阶段的格式不同。链接阶段每个.o文件都是一个独立的ELF文件,为了效率和便利性他们的段需要进行合并才能生成对应的可执行文件。

ELF文件包含一个Header描述文件的基本信息;
程序头表告诉系统如何构建进程的内存镜像,因此只有可执行文件有程序头表;
Sections描述了链接过程中的需要的符号表、数据、指令等信息,而在可执行文件中是Segments,是经过合并的Secitons;
节/段头表指明了对应section/segment在文件中的偏移,链接阶段的ELF文件必须包含该表头;
而每个节/段头描述了对应的section/segment的大小,入口等基本信息。

2.1. ELF Header

32bit和64bit的区别仅仅是字长的区别,字段上没有实际上的差别。

  • 魔数: 取值为固定的0x7f E L F,标记当前文件为一个ELF文件;
  • 位宽:0:表示非法的类别;1:表示32bit;2:表示64bit;
  • 端模式:0表示非法;1表示小端;2表示大端;
  • 版本
  • 目标系统体系结构
  • 程序虚拟入口地址
  • 程序头表的偏移
  • 段/节头表的偏移
  • 处理器相关标志位
  • ELF Header大小
  • 程序头表中单项的大小
  • 程序头表中的项数
  • 节表中单项的大小
  • 节表中项的数量
  • 节表中节名的索引

下面是一个例子:

root@firefly:~/work/test# readelf -h test
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           AArch64
  Version:                           0x1
  Entry point address:               0x660
  Start of program headers:          64 (bytes into file)
  Start of section headers:          10064 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         33
  Section header string table index: 32

2.2. 程序头表

可执行文件或者共享目标文件的程序头部是一个结构数组,每个结构描述了一个段 或者系统准备程序执行所必需的其它信息。程序头表描述了ELF文件中Segment在文件中的布局,描述了OS该如何装载可执行文件到内存。

  • 当前Segment的类型:可装载段;动态段;字符串等;
  • 当前段相对于文件起始位置的偏移量
  • 段的第一个字节将被映射到到内存中的虚拟地址
  • 段在文件映像中所占的字节数,可能为 0;
  • 段在内存映像中占用的字节数,可能为 0;
  • 段相关的标志;
  • 段在文件中和内存中如何对齐:0和1表示不需要对齐;其他值必须为2的幂次方,且必须p_addr ∣ p_align == p_offset ∣ palign。
root@firefly:~/work/test# readelf -l test

Elf file type is DYN (Shared object file)
Entry point 0x660
There are 9 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x00000000000001f8 0x00000000000001f8  R      0x8
  INTERP         0x0000000000000238 0x0000000000000238 0x0000000000000238
                 0x000000000000001b 0x000000000000001b  R      0x1
      [Requesting program interpreter: /lib/ld-linux-aarch64.so.1]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000abc 0x0000000000000abc  R E    0x10000
  LOAD           0x0000000000000d80 0x0000000000010d80 0x0000000000010d80
                 0x0000000000000290 0x0000000000000298  RW     0x10000
  DYNAMIC        0x0000000000000d90 0x0000000000010d90 0x0000000000010d90
                 0x00000000000001f0 0x00000000000001f0  RW     0x8
  NOTE           0x0000000000000254 0x0000000000000254 0x0000000000000254
                 0x0000000000000044 0x0000000000000044  R      0x4
  GNU_EH_FRAME   0x0000000000000938 0x0000000000000938 0x0000000000000938
                 0x0000000000000054 0x0000000000000054  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x0000000000000d80 0x0000000000010d80 0x0000000000010d80
                 0x0000000000000280 0x0000000000000280  R      0x1

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
   03     .init_array .fini_array .dynamic .got .data .bss
   04     .dynamic
   05     .note.gnu.build-id .note.ABI-tag
   06     .eh_frame_hdr
   07
   08     .init_array .fini_array .dynamic .got

2.3. 节头表

节头表描述了ELF文件中的节的基本信息。可执行文件不一定由节头表但是一定有节,节头表可利用特殊的方式去除。

段和节的区别是:

*   段包含了程序装载可执行的基本信息,段告诉OS如何装载当前段到虚拟内存以及当前段的权限等和执行相关的信息,一个段可以包含0个或多个节;
*   节包含了程序的代码和数据等内容,链接器会将多个节合并为一个段。

包括一下信息:

  • 节名称
  • 节的类型和语义
  • 装载信息
  • 当前节的首地址相对于文件的偏移
  • 节的大小
  • 地址约束对齐
  • 其他信息
root@firefly:~/work/test# readelf -S test
There are 33 section headers, starting at offset 0x2750:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000000238  00000238
       000000000000001b  0000000000000000   A       0     0     1
  [ 2] .note.gnu.build-i NOTE             0000000000000254  00000254
       0000000000000024  0000000000000000   A       0     0     4
  [ 3] .note.ABI-tag     NOTE             0000000000000278  00000278
       0000000000000020  0000000000000000   A       0     0     4
  [ 4] .gnu.hash         GNU_HASH         0000000000000298  00000298
       000000000000001c  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           00000000000002b8  000002b8
       00000000000000f0  0000000000000018   A       6     3     8
  [ 6] .dynstr           STRTAB           00000000000003a8  000003a8
       0000000000000089  0000000000000000   A       0     0     1
  [ 7] .gnu.version      VERSYM           0000000000000432  00000432
       0000000000000014  0000000000000002   A       5     0     2
  [ 8] .gnu.version_r    VERNEED          0000000000000448  00000448
       0000000000000020  0000000000000000   A       6     1     8
  [ 9] .rela.dyn         RELA             0000000000000468  00000468
       00000000000000f0  0000000000000018   A       5     0     8
  [10] .rela.plt         RELA             0000000000000558  00000558
       0000000000000078  0000000000000018  AI       5    21     8
  [11] .init             PROGBITS         00000000000005d0  000005d0
       0000000000000014  0000000000000000  AX       0     0     4
  [12] .plt              PROGBITS         00000000000005f0  000005f0
       0000000000000070  0000000000000010  AX       0     0     16
  [13] .text             PROGBITS         0000000000000660  00000660
       0000000000000294  0000000000000000  AX       0     0     8
  [14] .fini             PROGBITS         00000000000008f4  000008f4
       0000000000000010  0000000000000000  AX       0     0     4
  [15] .rodata           PROGBITS         0000000000000908  00000908
       000000000000002d  0000000000000000   A       0     0     8
  [16] .eh_frame_hdr     PROGBITS         0000000000000938  00000938
       0000000000000054  0000000000000000   A       0     0     4
  [17] .eh_frame         PROGBITS         0000000000000990  00000990
       000000000000012c  0000000000000000   A       0     0     8
  [18] .init_array       INIT_ARRAY       0000000000010d80  00000d80
       0000000000000008  0000000000000008  WA       0     0     8
  [19] .fini_array       FINI_ARRAY       0000000000010d88  00000d88
       0000000000000008  0000000000000008  WA       0     0     8
  [20] .dynamic          DYNAMIC          0000000000010d90  00000d90
       00000000000001f0  0000000000000010  WA       6     0     8
  [21] .got              PROGBITS         0000000000010f80  00000f80
       0000000000000080  0000000000000008  WA       0     0     8
  [22] .data             PROGBITS         0000000000011000  00001000
       0000000000000010  0000000000000000  WA       0     0     8
  [23] .bss              NOBITS           0000000000011010  00001010
       0000000000000008  0000000000000000  WA       0     0     1
  [24] .comment          PROGBITS         0000000000000000  00001010
       000000000000002b  0000000000000001  MS       0     0     1
  [25] .debug_aranges    PROGBITS         0000000000000000  0000103b
       0000000000000030  0000000000000000           0     0     1
  [26] .debug_info       PROGBITS         0000000000000000  0000106b
       00000000000003ea  0000000000000000           0     0     1
  [27] .debug_abbrev     PROGBITS         0000000000000000  00001455
       000000000000011f  0000000000000000           0     0     1
  [28] .debug_line       PROGBITS         0000000000000000  00001574
       0000000000000147  0000000000000000           0     0     1
  [29] .debug_str        PROGBITS         0000000000000000  000016bb
       00000000000002b8  0000000000000001  MS       0     0     1
  [30] .symtab           SYMTAB           0000000000000000  00001978
       0000000000000960  0000000000000018          31    74     8
  [31] .strtab           STRTAB           0000000000000000  000022d8
       000000000000033a  0000000000000000           0     0     1
  [32] .shstrtab         STRTAB           0000000000000000  00002612
       000000000000013a  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  p (processor specific)

2.4. 一些特殊的节

 ELF文件中有一些预定义的节来保存程序、数据和一些控制信息,这些节被用来链接或者装载程序。每个操作系统都支持一组链接模式,主要分为两类(也就是常说的动态库和静态库):

  • Static:静态绑定的一组目标文件、系统库和库档案(比如静态库),解析包含的符号引用并创建一个完全自包含的可执行文件;
  • Dynamic:一组目标文件、库、系统共享资源和其他共享库链接在一起创建可执行文件。当加载此可执行文件时必须使系统中其他共享资源和动态库可用,程序才能正常运行。

库文件无论是动态库还是静态库在其文件中都包含对应的节,一些特殊的节其功能如下:

.bss,类型SHT_NOBITS,属性SHF_ALLOC|SHF_WRITE:存储未经初始化的数据。根据定义程序开始执行时,系统会将这些数据初始化为0,且此节不占用文件空间;
.comment,类型SHT_PROGBITS,属性none:存储版本控制信息;
.data,类型SHT_PROGBITS,属性SHF_ALLOC|SHF_WRITE:存放初始化的数据;
.data1,类型SHT_PROGBITS,属性SHF_ALLOC|SHF_WRITE:存放初始化的数据;
.debug,类型SHT_PROGBITS,属性none:存放用于符号调试的信息;
.dynamic,类型SHT_DYNAMIC,属性SHF_ALLOC,是否有属性SHF_WRITE屈居于处理器:包含动态链接的信息,
.hash,类型SHT_HASH,属性SHF_ALLOC:
.line,类型SHT_PROGBITS,属性none:存储调试的行号信息,描述源代码和机器码之间的对应关系;
.note,类型SHT_NOTE,属性none:
.rodata,类型SHT_PROGBITS,属性SHF_ALLOC:存储只读数据;
.rodata1,类型SHT_PROGBITS,属性SHF_ALLOC:存储只读数据;
.shstrtab,类型SHT_STRTAB,属性none:存储节的名称;
.strtab,类型SHT_STRTAB:存储常见的与符号表关联的字符串。如果文件有一个包含符号字符串表的可加载段,则该段的属性将包括 SHF_ALLOC 位; 否则,该位将关闭;
.symtab,类型SHT_SYMTAB,属性``````:存储一个符号表。如果文件具有包含符号表的可加载段,则该节的属性将包括 SHF_ALLOC 位;否则,该位将关闭;
.text,类型SHT_PROGBITS,属性SHF_ALLOC|SHF_EXECINSTR:存储程序的代码指令;
.dynstr,类型SHT_STRTAB,属性SHF_ALLOC:存储动态链接所需的字符串,最常见的是表示与符号表条目关联的名称的字符串;
.dynsym,类型SHT_DYNSYM,属性SHF_ALLOC:存储动态链接符号表;
.fini,类型SHT_PROGBITS,属性SHF_ALLOC|SHF_EXECINSTR:存储有助于进程终止代码的可执行指令。 当程序正常退出时,系统执行本节代码;
.init,类型SHT_PROGBITS,属性SHF_ALLOC|SHF_EXECINSTR:存储有助于进程初始化代码的可执行指令。 当程序开始运行时,系统会在调用主程序入口点(C 程序称为 main)之前执行本节中的代码;
.interp,类型SHT_PROGBITS:保存程序解释器的路径名。 如果文件有一个包含该节的可加载段,则该节的属性将包括 SHF_ALLOC 位; 否则,该位将关闭;
.relname,类型SHT_REL:包含重定位信息。如果文件具有包含重定位的可加载段,则这些部分的属性将包括 SHF_ALLOC 位;否则,该位将关闭。通常,名称由 重定位适用的部分。因此.text的重定位部分通常具有名称.rel.text或.rela.text;
.relaname,类型SHT_RELA:同relname。
其他:对于C++程序有些版本会有.ctors和dtors两个节存储构造和析构相关的代码。

带有点 (.) 前缀的部分名称是为系统保留的,但如果它们的现有含义令人满意,应用程序可以使用这些部分。 应用程序可以使用不带前缀的名称以避免与系统部分冲突。 目标文件格式允许定义不在上面列表中的部分。 一个目标文件可能有多个同名的部分。

2.5. 字符串表

字符串表是一个存储字符串的表格,而每个字符串是以NULL也就是\0为结尾的。字符串表格中索引为0处的字符串被定义为空字符串。符号表中保存的字符串是节名和目标文件中使用到的符号。而需要使用对应字符串时,只需要在需要使用的地方指明对应字符在字符串表中的索引即可,使用的字符串就是索引处到第一个\0之间的字符串

2.6. 符号表

目标文件的符号表包含定位和重定位程序的符号定义和引用所需的信息。符号表索引是该数组的下标。索引0既指定表中的第一个条目,又用作未定义的符号索引。

root@firefly:~/work/test# readelf -s test

Symbol table '.dynsym' contains 10 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000000005d0     0 SECTION LOCAL  DEFAULT   11
     2: 0000000000011000     0 SECTION LOCAL  DEFAULT   22
     3: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab
     4: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.17 (2)
     5: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.17 (2)
     6: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     7: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND abort@GLIBC_2.17 (2)
     8: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
     9: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.17 (2)

Symbol table '.symtab' contains 100 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000238     0 SECTION LOCAL  DEFAULT    1
     2: 0000000000000254     0 SECTION LOCAL  DEFAULT    2
     3: 0000000000000278     0 SECTION LOCAL  DEFAULT    3
     4: 0000000000000298     0 SECTION LOCAL  DEFAULT    4
     5: 00000000000002b8     0 SECTION LOCAL  DEFAULT    5
     6: 00000000000003a8     0 SECTION LOCAL  DEFAULT    6
     7: 0000000000000432     0 SECTION LOCAL  DEFAULT    7
     8: 0000000000000448     0 SECTION LOCAL  DEFAULT    8
     9: 0000000000000468     0 SECTION LOCAL  DEFAULT    9
    10: 0000000000000558     0 SECTION LOCAL  DEFAULT   10
    11: 00000000000005d0     0 SECTION LOCAL  DEFAULT   11
    12: 00000000000005f0     0 SECTION LOCAL  DEFAULT   12
    13: 0000000000000660     0 SECTION LOCAL  DEFAULT   13
    14: 00000000000008f4     0 SECTION LOCAL  DEFAULT   14
    15: 0000000000000908     0 SECTION LOCAL  DEFAULT   15
    16: 0000000000000938     0 SECTION LOCAL  DEFAULT   16
    17: 0000000000000990     0 SECTION LOCAL  DEFAULT   17
    18: 0000000000010d80     0 SECTION LOCAL  DEFAULT   18
    19: 0000000000010d88     0 SECTION LOCAL  DEFAULT   19
    20: 0000000000010d90     0 SECTION LOCAL  DEFAULT   20
    21: 0000000000010f80     0 SECTION LOCAL  DEFAULT   21
    22: 0000000000011000     0 SECTION LOCAL  DEFAULT   22
    23: 0000000000011010     0 SECTION LOCAL  DEFAULT   23
    24: 0000000000000000     0 SECTION LOCAL  DEFAULT   24
    25: 0000000000000000     0 SECTION LOCAL  DEFAULT   25
    26: 0000000000000000     0 SECTION LOCAL  DEFAULT   26
    27: 0000000000000000     0 SECTION LOCAL  DEFAULT   27
    28: 0000000000000000     0 SECTION LOCAL  DEFAULT   28
    29: 0000000000000000     0 SECTION LOCAL  DEFAULT   29
    30: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /usr/lib/gcc/aarch64-linu
    31: 0000000000000278     0 NOTYPE  LOCAL  DEFAULT    3 $d
    32: 0000000000000660     0 NOTYPE  LOCAL  DEFAULT   13 $x
    33: 0000000000000908     0 NOTYPE  LOCAL  DEFAULT   15 $d
    34: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /usr/lib/gcc/aarch64-linu
    35: 0000000000000698     0 NOTYPE  LOCAL  DEFAULT   13 $x
    36: 0000000000000698    20 FUNC    LOCAL  DEFAULT   13 call_weak_fn
    37: 00000000000005d0     0 NOTYPE  LOCAL  DEFAULT   11 $x
    38: 00000000000008f4     0 NOTYPE  LOCAL  DEFAULT   14 $x
    39: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /usr/lib/gcc/aarch64-linu
    40: 00000000000005dc     0 NOTYPE  LOCAL  DEFAULT   11 $x
    41: 00000000000008fc     0 NOTYPE  LOCAL  DEFAULT   14 $x
    42: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    43: 00000000000006b0     0 NOTYPE  LOCAL  DEFAULT   13 $x
    44: 00000000000006b0     0 FUNC    LOCAL  DEFAULT   13 deregister_tm_clones
    45: 00000000000006e0     0 FUNC    LOCAL  DEFAULT   13 register_tm_clones
    46: 0000000000011008     0 NOTYPE  LOCAL  DEFAULT   22 $d
    47: 0000000000000720     0 FUNC    LOCAL  DEFAULT   13 __do_global_dtors_aux
    48: 0000000000011010     1 OBJECT  LOCAL  DEFAULT   23 completed.9189
    49: 0000000000010d88     0 NOTYPE  LOCAL  DEFAULT   19 $d
    50: 0000000000010d88     0 OBJECT  LOCAL  DEFAULT   19 __do_global_dtors_aux_fin
    51: 0000000000000768     0 FUNC    LOCAL  DEFAULT   13 frame_dummy
    52: 0000000000010d80     0 NOTYPE  LOCAL  DEFAULT   18 $d
    53: 0000000000010d80     0 OBJECT  LOCAL  DEFAULT   18 __frame_dummy_init_array_
    54: 00000000000009a4     0 NOTYPE  LOCAL  DEFAULT   17 $d
    55: 0000000000011010     0 NOTYPE  LOCAL  DEFAULT   23 $d
    56: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS test.c
    57: 000000000000076c     0 NOTYPE  LOCAL  DEFAULT   13 $x
    58: 0000000000000910     0 NOTYPE  LOCAL  DEFAULT   15 $d
    59: 0000000000000a08     0 NOTYPE  LOCAL  DEFAULT   17 $d
    60: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS elf-init.oS
    61: 0000000000000870     0 NOTYPE  LOCAL  DEFAULT   13 $x
    62: 0000000000000a70     0 NOTYPE  LOCAL  DEFAULT   17 $d
    63: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    64: 0000000000000ab8     0 NOTYPE  LOCAL  DEFAULT   17 $d
    65: 0000000000000ab8     0 OBJECT  LOCAL  DEFAULT   17 __FRAME_END__
    66: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS
    67: 0000000000010d88     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_end
    68: 0000000000010d90     0 OBJECT  LOCAL  DEFAULT  ABS _DYNAMIC
    69: 0000000000010d80     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_start
    70: 0000000000000938     0 NOTYPE  LOCAL  DEFAULT   16 __GNU_EH_FRAME_HDR
    71: 0000000000010fc0     0 OBJECT  LOCAL  DEFAULT  ABS _GLOBAL_OFFSET_TABLE_
    72: 00000000000005d0     0 FUNC    LOCAL  DEFAULT   11 _init
    73: 00000000000005f0     0 NOTYPE  LOCAL  DEFAULT   12 $x
    74: 00000000000008f0     4 FUNC    GLOBAL DEFAULT   13 __libc_csu_fini
    75: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab
    76: 0000000000011000     0 NOTYPE  WEAK   DEFAULT   22 data_start
    77: 0000000000011010     0 NOTYPE  GLOBAL DEFAULT   23 __bss_start__
    78: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@@GLIBC_2.1
    79: 0000000000011018     0 NOTYPE  GLOBAL DEFAULT   23 _bss_end__
    80: 0000000000011010     0 NOTYPE  GLOBAL DEFAULT   22 _edata
    81: 00000000000008f4     0 FUNC    GLOBAL HIDDEN    14 _fini
    82: 0000000000011018     0 NOTYPE  GLOBAL DEFAULT   23 __bss_end__
    83: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
    84: 0000000000011000     0 NOTYPE  GLOBAL DEFAULT   22 __data_start
    85: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    86: 0000000000011008     0 OBJECT  GLOBAL HIDDEN    22 __dso_handle
    87: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND abort@@GLIBC_2.17
    88: 0000000000000908     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used
    89: 0000000000000870   124 FUNC    GLOBAL DEFAULT   13 __libc_csu_init
    90: 000000000000076c   100 FUNC    GLOBAL DEFAULT   13 fibonacci
    91: 0000000000011018     0 NOTYPE  GLOBAL DEFAULT   23 _end
    92: 0000000000000660     0 FUNC    GLOBAL DEFAULT   13 _start
    93: 0000000000011018     0 NOTYPE  GLOBAL DEFAULT   23 __end__
    94: 0000000000011010     0 NOTYPE  GLOBAL DEFAULT   23 __bss_start
    95: 0000000000000814    88 FUNC    GLOBAL DEFAULT   13 main
    96: 0000000000011010     0 OBJECT  GLOBAL HIDDEN    22 __TMC_END__
    97: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
    98: 00000000000007d0    68 FUNC    GLOBAL DEFAULT   13 get_fibonacci_sub
    99: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@@GLIBC_2.17

寄存器读写常用方法总结

寄存器读写常用方法总结

前言

嵌入式编程中 经常对寄存器进行读写操作,而寄存器的功能定义一般是按bit进行定义,所以寄存器的读写本质上是bit操作。为了后续参考,在此做总结。
本文包括的寄存器操作:

  • WRITE : reg写
  • READ:reg读
  • POLL:等待reg为目标值
  • SET: bit置位
  • CLR: bit清位
  • CLRSET:清某些bit位再置位

在开发中也会遇到assert、de-assert的说法,理解过来就是:
assert --> SET
de-assert --> CLR

WRITE

write寄存器接口linux kernel已经提供了,有多个版本:

arch/arm64/include/asm/io.h 中定义

#define writeb(v,c)             ({ __iowmb(); writeb_relaxed((v),(c)); })    // 写单byte
#define writew(v,c)             ({ __iowmb(); writew_relaxed((v),(c)); })    // 写两个byte,word
#define writel(v,c)             ({ __iowmb(); writel_relaxed((v),(c)); })    // 写四个byte,dword,最常使用
#define writeq(v,c)             ({ __iowmb(); writeq_relaxed((v),(c)); })    // 写八个byte,qword

上述写寄存器的具体实现没啥神奇的地方,通过汇编指令对地址进行,这里列出一个:

#define __raw_writel __raw_writel
static inline void __raw_writel(u32 val, volatile void __iomem *addr)
{
        asm volatile("str %w0, [%1]" : : "r" (val), "r" (addr));
}

在开发中,一般寄存器的长度是4个byte,最常使用的是writel,用法比较简单。
writel(val, addr) // 需要注意的是第一个参数是value,第二个参数是地址,这个不能搞错

READ

read接口和write接口一样,内核也已经提供了,同样有多个版本“
arch/arm64/include/asm/io.h 中定义

#define readb(c)                ({ u8  __v = readb_relaxed(c); __iormb(); __v; })      // 读单byte
#define readw(c)                ({ u16 __v = readw_relaxed(c); __iormb(); __v; })      // 读两个byte,word
#define readl(c)                ({ u32 __v = readl_relaxed(c); __iormb(); __v; })      // 读四个byte,dword,最常使用
#define readq(c)                ({ u64 __v = readq_relaxed(c); __iormb(); __v; })      // 读八个byte,qword

在开发中,一般寄存器的长度是4个byte,最常使用的是readl,用法比较简单。
u32 value = readl(addr)

POLL

poll操作一般用在设置reg后,等待某个寄存器的某些bit位为目标值。
实现上,本质是对READ和WRITE 接口的进一步封装。

void reg_poll(unsigned int addr, unsigned int mask, unsigned int value) {
    while( (readl(addr) & mask) != value) {
        msleep(10);
    }
}

SET

set操作准确来说应该是set bits,针对某些bit进行置位

void reg_setbits(unsigned int addr, unsigned int value) {
    writel((readl(addr) | value, addr)
}

注意 如果bit已经置位,value中的该bit位是0的话,也不能把该bit clr掉

CLR

clr操作准确来说应该是clr bits,针对某些bit进行清位

void reg_clrbits(unsigned int addr, unsigned int value) {
    writel((readl(addr) & (~value), addr)
}

注意 希望clr掉哪个bit,就将value中对应的bit置1

CLRSET

clrset操作先某些bit,再置某些bit

void reg_clrsetbits(unsigned int addr, unsigned int clr, unsigned int set) {
    writel((readl(addr) & (~clr) | set, addr)
}

ARM64汇编视角看函数调用过程

ARM64汇编视角看程序运行过程

参考:
ARM64的函数调用标准和栈布局 http://blog.itpub.net/70005277/viewspace-2870926/


1. 基础知识

函数调用标准(Procedure Call Standard,PCS)用来描述父/子函数是如何编译、链接的,特别是父函数和子函数之间调用关系的约定,如栈的布局、参数的传递等。每个处理器架构都有不同的函数调用标准,本章重点介绍ARM64的函数调用标准。
ARM公司有一份描述ARM64架构函数调用的标准和规范文档,这份文档是《Procedure Call Standard for ARM 64-Bit Architecture》。
在ARM64体系结构中,栈是从高地址往低地址生长。栈的起始地址称为栈底,而栈从高地址往低地址延伸到某个点称为栈顶。栈在函数调用过程中起到非常重要的作用,包括存储函数使用的局部变量、传递参数等。在函数调用过程中,栈是逐步生成的。为单个函数分配的栈空间,即从该函数栈底(高地址)到栈顶(低地址)这段空间称为栈帧(Stack Frame)。
ARM64提供了31个通用寄存器,各个寄存器的指导用途如下:

  • x0~x7:传递子程序的参数和返回值,使用时不需要保存,多余的参数用堆栈传递,64位的返回结果保存在x0中。
  • x8:用于保存子程序的返回地址,使用时不需要保存。
  • x9~x15:临时寄存器,也叫可变寄存器,子程序使用时不需要保存。
  • x16~x17:子程序内部调用寄存器(IPx),使用时不需要保存,尽量不要使用。
  • x18:平台寄存器,它的使用与平台相关,尽量不要使用。
  • x19~x28:临时寄存器,子程序使用时必须保存。
  • x29:帧指针寄存器(FP),用于连接栈帧,使用时必须保存。
  • x30:链接寄存器(LR),用于保存子程序的返回地址。
  • x31:堆栈指针寄存器(SP),用于指向每个函数的栈顶。

下面用具体的例子学习函数调用过程中,栈的使用和变化。

2. 程序

test.c

#include <stdio.h>
#include <stdlib.h>

// F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)
int fibonacci(unsigned int num) {
    if (num == 0 )
        return 0;
    if (num == 1)
        return 1;

    return (fibonacci(num -1) + fibonacci(num -2));    // 断点3
}

int get_fibonacci_sub(int num1, int num2) {
        int a = 0;
        int b = 0;

        a = fibonacci(num1);    // 断点2
        b = fibonacci(num2);    
    return a - b;
}

int main(int argc, char *argv[]) {
    int a = 4;
    int b = 5;
    int sub = 0;

    sub = get_fibonacci_sub(b, a);    // 断点1

    printf("the fibonacci%d - fibonacci%d is %d\n", b, a, sub);
    return 0;
}

3. 反汇编

为了方便查看结果,在开发板上安装了gcc、gdb,下面的操作都是在开发板上。

编译:
gcc -o test test.c

反汇编:
objdump -d test > test.s

针对编译生成的test的可执行程序,反汇编出汇编code:

……
000000000000076c <fibonacci>:
 76c:   a9bd7bfd        stp     x29, x30, [sp, #-48]!
 770:   910003fd        mov     x29, sp
 774:   f9000bf3        str     x19, [sp, #16]
 778:   b9002fe0        str     w0, [sp, #44]
 77c:   b9402fe0        ldr     w0, [sp, #44]
 780:   7100001f        cmp     w0, #0x0
 784:   54000061        b.ne    790 <fibonacci+0x24>  // b.any
 788:   52800000        mov     w0, #0x0                        // #0
 78c:   1400000e        b       7c4 <fibonacci+0x58>
 790:   b9402fe0        ldr     w0, [sp, #44]
 794:   7100041f        cmp     w0, #0x1
 798:   54000061        b.ne    7a4 <fibonacci+0x38>  // b.any
 79c:   52800020        mov     w0, #0x1                        // #1
 7a0:   14000009        b       7c4 <fibonacci+0x58>
 7a4:   b9402fe0        ldr     w0, [sp, #44]
 7a8:   51000400        sub     w0, w0, #0x1
 7ac:   97fffff0        bl      76c <fibonacci>
 7b0:   2a0003f3        mov     w19, w0
 7b4:   b9402fe0        ldr     w0, [sp, #44]
 7b8:   51000800        sub     w0, w0, #0x2
 7bc:   97ffffec        bl      76c <fibonacci>
 7c0:   0b000260        add     w0, w19, w0
 7c4:   f9400bf3        ldr     x19, [sp, #16]
 7c8:   a8c37bfd        ldp     x29, x30, [sp], #48
 7cc:   d65f03c0        ret

00000000000007d0 <get_fibonacci_sub>:
 7d0:   a9bd7bfd        stp     x29, x30, [sp, #-48]!
 7d4:   910003fd        mov     x29, sp
 7d8:   b9001fe0        str     w0, [sp, #28]
 7dc:   b9001be1        str     w1, [sp, #24]
 7e0:   b9002bff        str     wzr, [sp, #40]
 7e4:   b9002fff        str     wzr, [sp, #44]
 7e8:   b9401fe0        ldr     w0, [sp, #28]
 7ec:   97ffffe0        bl      76c <fibonacci>
 7f0:   b9002be0        str     w0, [sp, #40]
 7f4:   b9401be0        ldr     w0, [sp, #24]
 7f8:   97ffffdd        bl      76c <fibonacci>
 7fc:   b9002fe0        str     w0, [sp, #44]
 800:   b9402be1        ldr     w1, [sp, #40]
 804:   b9402fe0        ldr     w0, [sp, #44]
 808:   4b000020        sub     w0, w1, w0
 80c:   a8c37bfd        ldp     x29, x30, [sp], #48
 810:   d65f03c0        ret

0000000000000814 <main>:
 814:   a9bd7bfd        stp     x29, x30, [sp, #-48]!
 818:   910003fd        mov     x29, sp
 81c:   b9001fe0        str     w0, [sp, #28]
 820:   f9000be1        str     x1, [sp, #16]
 824:   52800080        mov     w0, #0x4                        // #4
 828:   b90027e0        str     w0, [sp, #36]
 82c:   528000a0        mov     w0, #0x5                        // #5
 830:   b9002be0        str     w0, [sp, #40]
 834:   b9002fff        str     wzr, [sp, #44]
 838:   b94027e1        ldr     w1, [sp, #36]
 83c:   b9402be0        ldr     w0, [sp, #40]
 840:   97ffffe4        bl      7d0 <get_fibonacci_sub>
 844:   b9002fe0        str     w0, [sp, #44]
 848:   b9402fe3        ldr     w3, [sp, #44]
 84c:   b94027e2        ldr     w2, [sp, #36]
 850:   b9402be1        ldr     w1, [sp, #40]
 854:   90000000        adrp    x0, 0 <_init-0x5d0>
 858:   91244000        add     x0, x0, #0x910
 85c:   97ffff7d        bl      650 <printf@plt>
 860:   52800000        mov     w0, #0x0                        // #0
 864:   a8c37bfd        ldp     x29, x30, [sp], #48
 868:   d65f03c0        ret
 86c:   d503201f        nop
……

上面只列出了部分反汇编结果,其他和启动框架相关的隐去,后续再学习,当前只关注C code的汇编结果。

4. 运行过程

4.1. main 函数

一般来说main函数是第一个被调用的函数,实际上它是启动框架中的约定好的函数名称,也是被调用的函数。因此,相关的调用信息也需要被保存。
stp 指令是 str 的变种指令,p 可以理解成 pair 的意思,可以同时操作两个寄存器。

0000000000000814 <main>:
 814:   a9bd7bfd        stp     x29, x30, [sp, #-48]!          // 将 x29, x30 的值存入 sp 偏移 -48 个字节的位置,注意后面的感叹号,此句执行结束后,sp的值也改变了,即sp指向base-48
 818:   910003fd        mov     x29, sp                        // sp->x29, 它俩都执行了base-48
 81c:   b9001fe0        str     w0, [sp, #28]                  // 参数1,也就是argc,放到栈的base-48+28位置,注意这里的argc是32bit,所以使用w0
 820:   f9000be1        str     x1, [sp, #16]                  // 参数2,argv,放到栈的base-48+16位置
 824:   52800080        mov     w0, #0x4                       // 立即数4 放到w0
 828:   b90027e0        str     w0, [sp, #36]                  // 局部变量a,入栈
 82c:   528000a0        mov     w0, #0x5                       // 立即数5 放到w0
 830:   b9002be0        str     w0, [sp, #40]                   // 局部变量b,入栈    立即数不能直接入栈吗? ** 只能通过寄存器转储 **
 834:   b9002fff        str     wzr, [sp, #44]                 // 局部变量sub
 838:   b94027e1        ldr     w1, [sp, #36]                   // 从这里开始是准备调用get_fibonacci_sub, 把两个参数分别放到w0、w1
 83c:   b9402be0        ldr     w0, [sp, #40]
 840:   97ffffe4        bl      7d0 <get_fibonacci_sub>
 844:   b9002fe0        str     w0, [sp, #44]
 848:   b9402fe3        ldr     w3, [sp, #44]
 84c:   b94027e2        ldr     w2, [sp, #36]
 850:   b9402be1        ldr     w1, [sp, #40]
 854:   90000000        adrp    x0, 0 <_init-0x5d0>
 858:   91244000        add     x0, x0, #0x910
 85c:   97ffff7d        bl      650 <printf@plt>
 860:   52800000        mov     w0, #0x0                        // #0
 864:   a8c37bfd        ldp     x29, x30, [sp], #48
 868:   d65f03c0        ret
 86c:   d503201f        nop

在调用get_fibonacci_sub之前,打下断电看各个寄存器和栈的状态

4.1.1. 断点1

(gdb) b test.c:29
Breakpoint 1 at 0x838: file test.c, line 29.
(gdb)
Note: breakpoint 1 also set at pc 0x838.
Breakpoint 2 at 0x838: file test.c, line 29.
(gdb)
Note: breakpoints 1 and 2 also set at pc 0x838.
Breakpoint 3 at 0x838: file test.c, line 29.
(gdb) run
`/root/work/test/test' has changed; re-reading symbols.
Starting program: /root/work/test/test

Breakpoint 1, main (argc=1, argv=0x7ffffff358) at test.c:29
29          sub = get_fibonacci_sub(b, a);
(gdb) info frame
Stack level 0, frame at 0x7ffffff200:
 pc = 0x5555555838 in main (test.c:29); saved pc = 0x7fb7e7ae10
 source language c.
 Arglist at 0x7ffffff1d0, args: argc=1, argv=0x7ffffff358
 Locals at 0x7ffffff1d0, Previous frame's sp is 0x7ffffff200
 Saved registers:
  x29 at 0x7ffffff1d0, x30 at 0x7ffffff1d8
(gdb) info reg
x0             0x5                 5
x1             0x7ffffff358        549755810648
x2             0x7ffffff368        549755810664
x3             0x5555555814        366503876628
x4             0x0                 0
x5             0xfcff643a2109a679  -216344056265333127
x6             0x7fb7fc9b10        548547631888
x7             0x4010040100        275146604800
x8             0xffffffffffffffff  -1
x9             0x3ffffffffffff     1125899906842623
x10            0x0                 0
x11            0x0                 0
x12            0x7fb7e5de48        548546141768
x13            0x0                 0
x14            0x0                 0
x15            0x6fffff47          1879048007
x16            0x0                 0
x17            0x0                 0
x18            0x73516240          1934713408
x19            0x5555555870        366503876720
x20            0x0                 0
x21            0x5555555660        366503876192
x22            0x0                 0
x23            0x0                 0
x24            0x0                 0
x25            0x0                 0
x26            0x0                 0
x27            0x0                 0
x28            0x0                 0
x29            0x7ffffff1d0        549755810256
x30            0x7fb7e7ae10        548546260496
sp             0x7ffffff1d0        0x7ffffff1d0
pc             0x5555555838        0x5555555838 <main+36>
cpsr           0x60000000          [ EL=0 C Z ]
fpsr           0x0                 0
fpcr           0x0                 0
(gdb) x/16xw 0x7ffffff1d0
0x7ffffff1d0:   0xfffff200      0x0000007f      0xb7e7ae10      0x0000007f
0x7ffffff1e0:   0xfffff358      0x0000007f      0xb7e7add4      0x00000001
0x7ffffff1f0:   0x55555870      0x00000004      0x00000005      0x00000000
0x7ffffff200:   0x00000000      0x00000000      0x55555694      0x00000055

4.2. get_fibonacci_sub

00000000000007d0 <get_fibonacci_sub>:
 7d0:   a9bd7bfd        stp     x29, x30, [sp, #-48]!  // 创建了新的栈帧,帧大小48bytes,同时将LR、FP入栈
 7d4:   910003fd        mov     x29, sp                 // X29,sp同时指向了栈顶
 7d8:   b9001fe0        str     w0, [sp, #28]           // 参数1,入栈
 7dc:   b9001be1        str     w1, [sp, #24]           // 参数2,入栈
 7e0:   b9002bff        str     wzr, [sp, #40]          // 局部变量初始化
 7e4:   b9002fff        str     wzr, [sp, #44]          // 局部变量初始化
 7e8:   b9401fe0        ldr     w0, [sp, #28]           // 准备子函数的入参
 7ec:   97ffffe0        bl      76c <fibonacci>
 7f0:   b9002be0        str     w0, [sp, #40]
 7f4:   b9401be0        ldr     w0, [sp, #24]       
 7f8:   97ffffdd        bl      76c <fibonacci>
 7fc:   b9002fe0        str     w0, [sp, #44]
 800:   b9402be1        ldr     w1, [sp, #40]
 804:   b9402fe0        ldr     w0, [sp, #44]
 808:   4b000020        sub     w0, w1, w0
 80c:   a8c37bfd        ldp     x29, x30, [sp], #48
 810:   d65f03c0        ret

4.2.1. 断点2

(gdb) b test.c:19
Breakpoint 4 at 0x55555557e8: file test.c, line 19.
(gdb) continue
Continuing.

Breakpoint 4, get_fibonacci_sub (num1=5, num2=4) at test.c:19
19              a = fibonacci(num1);
(gdb) info frame
Stack level 0, frame at 0x7ffffff1d0:
 pc = 0x55555557e8 in get_fibonacci_sub (test.c:19); saved pc = 0x5555555844
 called by frame at 0x7ffffff200
 source language c.
 Arglist at 0x7ffffff1a0, args: num1=5, num2=4
 Locals at 0x7ffffff1a0, Previous frame's sp is 0x7ffffff1d0
 Saved registers:
  x29 at 0x7ffffff1a0, x30 at 0x7ffffff1a8
(gdb) info reg
x0             0x5                 5
x1             0x4                 4
x2             0x7ffffff368        549755810664
x3             0x5555555814        366503876628
x4             0x0                 0
x5             0xfcff643a2109a679  -216344056265333127
x6             0x7fb7fc9b10        548547631888
x7             0x4010040100        275146604800
x8             0xffffffffffffffff  -1
x9             0x3ffffffffffff     1125899906842623
x10            0x0                 0
x11            0x0                 0
x12            0x7fb7e5de48        548546141768
x13            0x0                 0
x14            0x0                 0
x15            0x6fffff47          1879048007
x16            0x0                 0
x17            0x0                 0
x18            0x73516240          1934713408
x19            0x5555555870        366503876720
x20            0x0                 0
x21            0x5555555660        366503876192
x22            0x0                 0
x23            0x0                 0
x24            0x0                 0
x25            0x0                 0
x26            0x0                 0
x27            0x0                 0
x28            0x0                 0
x29            0x7ffffff1a0        549755810208
x30            0x5555555844        366503876676
sp             0x7ffffff1a0        0x7ffffff1a0
pc             0x55555557e8        0x55555557e8 <get_fibonacci_sub+24>
cpsr           0x60000000          [ EL=0 C Z ]
fpsr           0x0                 0
fpcr           0x0                 0
(gdb) x/16xw 0x7ffffff1a0
0x7ffffff1a0:   0xfffff1d0      0x0000007f      0x55555844      0x00000055
0x7ffffff1b0:   0xfffff1c0      0x0000007f      0x00000004      0x00000005
0x7ffffff1c0:   0xfffff200      0x0000007f      0x00000000      0x00000000
0x7ffffff1d0:   0xfffff200      0x0000007f      0xb7e7ae10      0x0000007f

4.3. fibonacci

 76c:   a9bd7bfd        stp     x29, x30, [sp, #-48]!    // 创建了新的栈帧,帧大小48bytes,同时将LR、FP入栈
 770:   910003fd        mov     x29, sp                  // X29,sp同时指向了栈顶
 774:   f9000bf3        str     x19, [sp, #16]           // 这个函数要使用x19,所以先保存
 778:   b9002fe0        str     w0, [sp, #44]            // 参数入栈
 77c:   b9402fe0        ldr     w0, [sp, #44]            // 读取参数
 780:   7100001f        cmp     w0, #0x0                 // 
 784:   54000061        b.ne    790 <fibonacci+0x24>     // 不为0,跳转
 788:   52800000        mov     w0, #0x0                        // #0
 78c:   1400000e        b       7c4 <fibonacci+0x58>
 790:   b9402fe0        ldr     w0, [sp, #44]             // 读取参数
 794:   7100041f        cmp     w0, #0x1
 798:   54000061        b.ne    7a4 <fibonacci+0x38>      // 不为1,跳转
 79c:   52800020        mov     w0, #0x1                        // #1
 7a0:   14000009        b       7c4 <fibonacci+0x58>
 7a4:   b9402fe0        ldr     w0, [sp, #44]
 7a8:   51000400        sub     w0, w0, #0x1
 7ac:   97fffff0        bl      76c <fibonacci>
 7b0:   2a0003f3        mov     w19, w0
 7b4:   b9402fe0        ldr     w0, [sp, #44]
 7b8:   51000800        sub     w0, w0, #0x2
 7bc:   97ffffec        bl      76c <fibonacci>
 7c0:   0b000260        add     w0, w19, w0
 7c4:   f9400bf3        ldr     x19, [sp, #16]
 7c8:   a8c37bfd        ldp     x29, x30, [sp], #48
 7cc:   d65f03c0        ret

4.3.1. 断点3

(gdb) b test.c:11
Breakpoint 5 at 0x55555557a4: file test.c, line 11.
(gdb)
Note: breakpoint 5 also set at pc 0x55555557a4.
Breakpoint 6 at 0x55555557a4: file test.c, line 11.
(gdb) continue
Continuing.

Breakpoint 5, fibonacci (num=5) at test.c:11
11          return (fibonacci(num -1) + fibonacci(num -2));
(gdb) info frame
Stack level 0, frame at 0x7ffffff1a0:
 pc = 0x55555557a4 in fibonacci (test.c:11); saved pc = 0x55555557f0
 called by frame at 0x7ffffff1d0
 source language c.
 Arglist at 0x7ffffff170, args: num=5
 Locals at 0x7ffffff170, Previous frame's sp is 0x7ffffff1a0
 Saved registers:
  x19 at 0x7ffffff180, x29 at 0x7ffffff170, x30 at 0x7ffffff178
(gdb) info reg
x0             0x5                 5
x1             0x4                 4
x2             0x7ffffff368        549755810664
x3             0x5555555814        366503876628
x4             0x0                 0
x5             0xfcff643a2109a679  -216344056265333127
x6             0x7fb7fc9b10        548547631888
x7             0x4010040100        275146604800
x8             0xffffffffffffffff  -1
x9             0x3ffffffffffff     1125899906842623
x10            0x0                 0
x11            0x0                 0
x12            0x7fb7e5de48        548546141768
x13            0x0                 0
x14            0x0                 0
x15            0x6fffff47          1879048007
x16            0x0                 0
x17            0x0                 0
x18            0x73516240          1934713408
x19            0x5555555870        366503876720
x20            0x0                 0
x21            0x5555555660        366503876192
x22            0x0                 0
x23            0x0                 0
x24            0x0                 0
x25            0x0                 0
x26            0x0                 0
x27            0x0                 0
x28            0x0                 0
x29            0x7ffffff170        549755810160
x30            0x55555557f0        366503876592
sp             0x7ffffff170        0x7ffffff170
pc             0x55555557a4        0x55555557a4 <fibonacci+56>
cpsr           0x20000000          [ EL=0 C ]
fpsr           0x0                 0
fpcr           0x0                 0
(gdb) x/16xw 0x7ffffff180
0x7ffffff180:   0x55555870      0x00000055      0xb7fe10a4      0x0000007f
0x7ffffff190:   0xb7fc4c08      0x0000007f      0xb7fc4c08      0x00000005
0x7ffffff1a0:   0xfffff1d0      0x0000007f      0x55555844      0x00000055
0x7ffffff1b0:   0xfffff1c0      0x0000007f      0x00000004      0x00000005

C语言字符串与数字转换

C语言字符串与数字转换

参考:
http://www.verydoc.net/c/00000777.html

1. 前言

在开发中常常遇到字符串与数字的相互转换,在这里列一下常用的函数,以备不时之需。

2. 字符串转数字

ANSI C 规范定义了 atof()、atoi()、atol()、strtod()、strtol()、strtoul() 共6个可以将字符串转换为数字的函数。
在 C99 / C++11 规范中又新增了5个函数,分别是 atoll()、strtof()、strtold()、strtoll()、strtoull()。

2.1. 有符号数转换

2.1.1. atoi/atol/atoll

int atoi(con​​st char * str);
long atol(const char * str);
long long atoll(const char * str); (自C99以来)

【 头文件】
#include <stdlib.h>

【函数说明】
解释str指向的字节字符串中的整数值。
放弃任何空格字符,直到找到第一个非空白字符,然后采用尽可能多的字符以形成有效的整数表示并将它们转换为整数值。有效的整数值由以下部分组成:

  • (可选)加号或减号
  • 数字
  • 【返回值】
    整数值对应str成功的内容。 如果转换后的值超出了相应返回类型的范围,则返回值未定义。 如果不能执行转换,则返回0。

2.1.2. strtol/strtoll

long strtol(const char * str,char ** str_end,int base);(直到C99)
long strtol(const char * restrict str,char ** restrict str_end,int base);(自C99以来)
long long strtoll(const char * restrict str,char ** restrict str_end,int base);(自C99以来)

【头文件】
#include <stdlib.h>

【函数说明】
解释str指向的字节字符串中的整数值。
放弃任何空格字符(通过调用标识isspace()),直到找到第一个非空白字符,然后接收尽可能多的字符以形成有效的base-n(其中n = base)整数表示并将它们转换为整数值。有效的整数值由以下部分组成:

  • (可选)加号或减号
  • (可选)prefix(0)指示八进制基数(只适用于基数为8或​0​)
  • (可选)前缀(0x或0X)表示十六进制基数(仅适用于基数为16或​0​)
  • 数字序列

base的有效值集合是{0,2,3,...,36}。base-2整数的有效数字集合是{0,1},对于base-3整数是{0,1,2},依此类推。对于大于等于的基数10,有效数字包含字母字符,从Aa基数为11的整数开始,到Zz基数为36的整数。字符的情况被忽略。

其他数字格式可以被当前安装的C语言环境接受。

如果基数的值是​0​,数字基地是自动检测:如果前缀是0,基地是八进制的,如果前缀是0x或0X,基地是十六进制,否则基数是十进制。

如果减号是输入序列的一部分,则根据数字序列计算的数值将被否定,如同在结果类型中使用一元减号一样。

这些函数将str_end指向的指针设置为指向经过最后解释的字符的字符。 如果str_end是NULL,它将被忽略。

如果str为空或者没有预期的形式,则不执行转换,并且(如果str_end不是NULL),则str的值将存储在str_end指向的对象中。

【返回值】

  • 如果成功,则返回与内容相对应的整数值str。
  • 如果转换后的值脱离的相应返回类型的范围时,发生错误的范围(设定errno到ERANGE)和LONG_MAX,LONG_MIN,LLONG_MAX或LLONG_MIN返回。
  • 如果不能执行转换,​0​则被返回。
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

int main(void)
{
    // parsing with error handling
    const char *p = "10 200000000000000000000000000000 30 -40 junk";
    printf("Parsing '%s':\n", p);
    char *end;
    for (long i = strtol(p, &end, 10);
         p != end;
         i = strtol(p, &end, 10))
    {
        printf("'%.*s' -> ", (int)(end-p), p);
        p = end;
        if (errno == ERANGE){
            printf("range error, got ");
            errno = 0;
        }
        printf("%ld\n", i);
    }

    // parsing without error handling
    printf("\"1010\" in binary  --> %ld\n", strtol("1010",NULL,2));
    printf("\"12\" in octal     --> %ld\n", strtol("12",NULL,8));
    printf("\"A\"  in hex       --> %ld\n", strtol("A",NULL,16));
    printf("\"junk\" in base-36 --> %ld\n", strtol("junk",NULL,36));
    printf("\"012\" in auto-detected base  --> %ld\n", strtol("012",NULL,0));
    printf("\"0xA\" in auto-detected base  --> %ld\n", strtol("0xA",NULL,0));
    printf("\"junk\" in auto-detected base -->  %ld\n", strtol("junk",NULL,0));
}

输出:

Parsing '10 200000000000000000000000000000 30 -40 junk':
'10' -> 10
' 200000000000000000000000000000' -> range error, got 9223372036854775807
' 30' -> 30
' -40' -> -40
"1010" in binary  --> 10
"12" in octal     --> 10
"A"  in hex       --> 10
"junk" in base-36 --> 926192
"012" in auto-detected base  --> 10
"0xA" in auto-detected base  --> 10
"junk" in auto-detected base -->  0

2.2. 无符号数转换

2.2.1. strtoul/strtoull

unsigned long strtoul(const char * str,char ** str_end,int base);
unsigned long strtoul(const char * restrict str,char ** restrict str_end,int base);
unsigned long long strtoull(const char * restrict str,char ** restrict str_end,int base);

【头文件】
#include <stdlib.h>

【函数说明】
解释str指向的字节字符串中的无符号整数值。
放弃任何空白字符(通过调用标识isspace()),直到找到第一个非空白字符,然后接收尽可能多的字符以形成有效的base-n(其中n = base)无符号整数表示并将它们转换为整数值。有效的无符号整数值由以下部分组成:

  • (可选)加号或减号
  • (可选)prefix(0)指示八进制基数(只适用于基数为8或​0​)
  • (可选)前缀(0x或0X)表示十六进制基数(仅适用于基数为16或​0​)
  • 数字序列

base的有效值集合是{0,1,2,3,...,36}。base-2整数的有效数字集合是{0,1},对于base-3整数是{0,1,2},依此类推。对于大于等于的基数10,有效数字包含字母字符,从Aa基数为11的整数开始,到Zz基数为36的整数。字符的情况被忽略。

其他数字格式可以被当前安装的C语言环境接受。

如果基数的值是​0​,数字基地是自动检测:如果前缀是0,基地是八进制的,如果前缀是0x或0X,基地是十六进制,否则基数是十进制。

如果减号是输入序列的一部分,则根据数字序列计算的数值将被否定,如同使用无符号整数环绕规则的结果类型中的一元减号一样。

这些函数将str_end指向的指针设置为指向经过最后解释的字符的字符。 如果str_end是NULL,它将被忽略。

【返回值】
整数值对应str成功的内容。 如果转换后的值超出了相应返回类型的范围,则会发生范围错误(errno设置为ERANGE),并返回ULONG_MAX或ULLONG_MAX。 如果不能执行转换,则返回0。

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

int main(void)
{
    const char *p = "10 200000000000000000000000000000 30 -40";
    printf("Parsing '%s':\n", p);
    char *end;
    for (unsigned long i = strtoul(p, &end, 10);
         p != end;
         i = strtoul(p, &end, 10))
    {
        printf("'%.*s' -> ", (int)(end-p), p);
        p = end;
        if (errno == ERANGE){
            printf("range error, got ");
            errno = 0;
        }
        printf("%lu\n", i);
    }
}
Parsing '10 200000000000000000000000000000 30 -40':
'10' -> 10
' 200000000000000000000000000000' -> range error, got 18446744073709551615
' 30' -> 30
' -40' -> 18446744073709551576

2.3. 浮点数据转换

2.3.1. atof

【头文件】
#include <stdlib.h>

【原型】
double atof(const char *nptr);

【函数说明】
解释str指向的字节串中的浮点值。
函数丢弃任何空格字符(由std :: isspace()确定),直到找到第一个非空白字符。 然后,它需要尽可能多的字符来形成有效的浮点表示并将它们转换为浮点值。 有效的浮点值可以是以下值之一:
有效的浮点值可以是以下值之一:

  • 进制浮点表达式。它由以下部分组成:
    • (可选)加号或减号
    • 非空十进制数字序列可选地包含小数点字符(由当前C确定locale)(定义有效数字)
    • (可选),e或者E跟随可选的负号或加号和非空序列的十进制数字(定义指数)
  • 二进制浮点表达式。它由以下部分组成:
    • (可选)加号或减号
    • 0x 或 0X
    • 非空的十六进制数字序列可选地包含小数点字符(由当前C确定locale)(定义有效数字)
    • (可选),p或者P跟随可选的负号或加号和非空序列的十进制数字(定义指数)
  • 无限表达。它由以下部分组成:
    • (可选)加号或减号
    • INF或者INFINITY无视事件
  • 非数字表达式。它由以下部分组成:
    • (可选)加号或减号
    • NAN或NAN(char_sequence)忽略该NAN部分的情况。char_sequence只能包含字母数字字符。结果是静态的NaN浮点值。
  • 任何其他可能被当前安装的C接受的表达式 locale

这些函数将str_end指向的指针设置为指向经过最后解释的字符的字符。 如果str_end是NULL,它将被忽略。

【返回值】
若成功,则返回double值对应str的内容。 如果转换后的值超出了返回类型的范围,则返回值未定义。 如果不能执行转换,则返回0.0。

2.3.2. strtof/strtod/strtold

float strtof(const char * restrict str,char ** restrict str_end);
double strtod(const char * str,char ** str_end);
double strtod(const char * restrict str,char ** restrict str_end);
long double strtold(const char * restrict str,char ** restrict str_end);

【头文件】
#include <stdlib.h>

【函数说明】
解释str指向的字节串中的浮点值。
函数丢弃任何空格字符(由std :: isspace()确定),直到找到第一个非空白字符。 然后,它需要尽可能多的字符来形成有效的浮点表示并将它们转换为浮点值。 有效的浮点值可以是以下值之一:

  • 进制浮点表达式。它由以下部分组成:
    • (可选)加号或减号
    • 非空十进制数字序列可选地包含小数点字符(由当前C确定locale)(定义有效数字)
    • (可选),e或者E跟随可选的负号或加号和非空序列的十进制数字(定义指数)
  • 二进制浮点表达式。它由以下部分组成:
    • (可选)加号或减号
    • 0x 或 0X
    • 非空的十六进制数字序列可选地包含小数点字符(由当前C确定locale)(定义有效数字)
    • (可选),p或者P跟随可选的负号或加号和非空序列的十进制数字(定义指数)
  • 无限表达。它由以下部分组成:
    • (可选)加号或减号
    • INF或者INFINITY无视事件
  • 非数字表达式。它由以下部分组成:
    • (可选)加号或减号
    • NAN或NAN(char_sequence)忽略该NAN部分的情况。char_sequence只能包含字母数字字符。结果是静态的NaN浮点值。
  • 任何其他可能被当前安装的C接受的表达式 locale

这些函数将str_end指向的指针设置为指向经过最后解释的字符的字符。 如果str_end是NULL,它将被忽略。

【返回值】
浮点值对应str的成功内容。 如果转换后的值超出相应返回类型的范围,则会发生范围错误,并返回HUGE_VAL,HUGE_VALF或HUGE_VALL。 如果不能执行转换,则返回0。

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

int main(void)
{
    // parsing with error handling
    const char *p = "111.11 -2.22 Nan nan(2) inF 0X1.BC70A3D70A3D7P+6  1.18973e+4932zzz";
    printf("Parsing '%s':\n", p);
    char *end;
    for (double f = strtod(p, &end); p != end; f = strtod(p, &end))
    {
        printf("'%.*s' -> ", (int)(end-p), p);
        p = end;
        if (errno == ERANGE){
            printf("range error, got ");
            errno = 0;
        }
        printf("%f\n", f);
    }

    // parsing without error handling
    printf("\"  -0.0000000123junk\"  -->  %g\n", strtod("  -0.0000000123junk", NULL));
    printf("\"junk\"                 -->  %g\n", strtod("junk", NULL));
}
Parsing '111.11 -2.22 Nan inF 0X1.BC70A3D70A3D7P+6  1.18973e+4932zzz':
'111.11' -> 111.110000
' -2.22' -> -2.220000
' Nan' -> nan
' nan(2)' -> nan
' inF' -> inf
' 0X1.BC70A3D70A3D7P+6' -> 111.110000
'  1.18973e+4932' -> range error, got inf
"  -0.0000000123junk"  -->  -1.23e-08
"junk"                 -->  0

3. 数字转字符串

非标准实现,在window平台下可以使用,跨平台到linux不支持:

    itoa()                将整型值转换为字符串
    ltoa()                将长整型值转换为字符串
    ultoa()               将无符号长整型值转换为字符串
    ecvt()    将双精度浮点型值转换为字符串,转换结果中不包含十进制小数点
    fcvt()    以指定位数为转换精度,余同ecvt()
    gcvt()    将双精度浮点型值转换为字符串,转换结果中包含十进制小数点    

更为通用的实现则是使用sprintf()函数

3.1. spintf

【头文件】
#include <stdio.h>
【原型】
int sprintf(char *str, const char *format, ...)

【函数说明】
str -- 这是指向一个字符数组的指针,该数组存储了 C 字符串。
format -- 这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier,具体讲解如下:

  • specifier(说明符)
    c   字符
    d 或 i   有符号十进制整数
    e   使用 e 字符的科学科学记数法(尾数和指数)
    E   使用 E 字符的科学科学记数法(尾数和指数)
    f   十进制浮点数
    g   自动选择 %e 或 %f 中合适的表示法
    G   自动选择 %E 或 %f 中合适的表示法
    o   有符号八进制
    s   字符的字符串
    u   无符号十进制整数
    x   无符号十六进制整数
    X   无符号十六进制整数(大写字母)
    p   指针地址
    n   无输出
    %   字符
  • flags(标识)
-
在给定的字段宽度内左对齐,默认是右对齐(参见 width 子说明符)。
+
强制在结果之前显示加号或减号(+ 或 -),即正数前面会显示 + 号。默认情况下,只有负数前面会显示一个 - 号。
(space) 
如果没有写入任何符号,则在该值前面插入一个空格。
#   
与 o、x 或 X 说明符一起使用时,非零值前面会分别显示 0、0x 或 0X。
与 e、E 和 f 一起使用时,会强制输出包含一个小数点,即使后边没有数字时也会显示小数点。默认情况下,如果后边没有数字时候,不会显示显示小数点。
与 g 或 G 一起使用时,结果与使用 e 或 E 时相同,但是尾部的零不会被移除。
0   
在指定填充 padding 的数字左边放置零(0),而不是空格(参见 width 子说明符)。
  • width(宽度)
(number)    要输出的字符的最小数目。如果输出的值短于该数,结果会用空格填充。如果输出的值长于该数,结果不会被截断。
*   宽度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。
  • .precision(精度)
.number
对于整数说明符(d、i、o、u、x、X):precision 指定了要写入的数字的最小位数。如果写入的值短于该数,结果会用前导零来填充。如果写入的值长于该数,结果不会被截断。精度为 0 意味着不写入任何字符。
对于 e、E 和 f 说明符:要在小数点后输出的小数位数。
对于 g 和 G 说明符:要输出的最大有效位数。
对于 s: 要输出的最大字符数。默认情况下,所有字符都会被输出,直到遇到末尾的空字符。
对于 c 类型:没有任何影响。
当未指定任何精度时,默认为 1。如果指定时不带有一个显式值,则假定为 0。
.*  
精度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。
  • length(长度)
h   参数被解释为短整型或无符号短整型(仅适用于整数说明符:i、d、o、u、x 和 X)。
l   参数被解释为长整型或无符号长整型,适用于整数说明符(i、d、o、u、x 和 X)及说明符 c(表示一个宽字符)和 s(表示宽字符字符串)。
L   参数被解释为长双精度型(仅适用于浮点数说明符:e、E、f、g 和 G)。
  • 附加参数 -- 根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。

【返回值】
如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。

#include <stdio.h>
#include <math.h>

int main()
{
   char str[80];

   sprintf(str, "Pi 的值 = %f", M_PI);
   puts(str);

   return(0);
}

linux oops分析方法

oops信息解读

转:如何解读内核的oops (qq.com)

[cc lang=c]

root@firefly:~/mnt/module# insmod oops_module.ko
[  867.140514] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[  867.141279] pgd = ffffffc0f0a65000
[  867.141582] [00000000] *pgd=0000000000000000, *pud=0000000000000000
[  867.142164] Internal error: Oops: 96000045 [#1] SMP
[  867.142592] Modules linked in: oops_module(O+)
[  867.143006] CPU: 4 PID: 1163 Comm: insmod Tainted: G           O    4.4.194+ #7
[  867.143649] Hardware name: Firefly-RK3399 Board (Linux Opensource) (DT)
[  867.144236] task: ffffffc0cdc44380 task.stack: ffffffc00a4fc000
[  867.144761] PC is at init_oopsdemo+0x24/0x38 [oops_module]
[  867.145247] LR is at init_oopsdemo+0x18/0x38 [oops_module]
[  867.145732] pc : [<ffffff8000ef0024>] lr : [<ffffff8000ef0018>] pstate: 40000145
[  867.146386] sp : ffffffc00a4ffc40
[  867.146688] x29: ffffffc00a4ffc40 x28: ffffff80081376d0
[  867.147178] x27: 0000000000000001 x26: ffffffc0cde6e880
[  867.147491] x25: 0000000000000001 x24: ffffff8000ef2050
[  867.147495] x23: 0000000000000000 x22: ffffff80095b7860
[  867.147498] x21: ffffffc0cdce10c0 x20: ffffff80095b7860
[  867.147501] x19: ffffff8000ef0000 x18: ffffff80897bfa97
[  867.147504] x17: 0000007fb096c8a0 x16: ffffff800813b204 Segmentation fau
lt
[  867.147508] x15: 0000000000000000 root@firefly:~/mx14: 00000000000224d6 nt/module#
[  867.147511] x13: 000000000000000a x12: 0000000000000030
[  867.147515] x11: 00000000fffffffe x10: ffffff80097bfa9f
[  867.147518] x9 : 0000000005f5e0ff x8 : ffffff8008463c3c
[  867.147522] x7 : ffffff80096280b0 x6 : 0000000000000022
[  867.147525] x5 : ffffffc0f7f24b38 x4 : 0000000000000001
[  867.147528] x3 : 0000000000000007 x2 : 0000000000000007
[  867.147534] x1 : 0000000019760817 x0 : 0000000000000000
[  867.147536]
[  867.147536] PC: 0xffffff8000eeffa4:
[  867.147550] ffa4  ******** ******** ******** ******** ******** ******** ******** ********
[  867.147561] ffc4  ******** ******** ******** ******** ******** ******** ******** ********
[  867.147572] ffe4  ******** ******** ******** ******** ******** ******** ******** a9bf7bfd
[  867.147581] 0004  910003fd aa1e03e0 d503201f 58000100 95ca7426 d2800000 528102e1 72a32ec1
[  867.147590] 0024  b9000001 a8c17bfd d65f03c0 00ef1024 ffffff80 a9bf7bfd 910003fd aa1e03e0
[  867.147599] 0044  d503201f 58000080 95ca7418 a8c17bfd d65f03c0 00ef1038 ffffff80 00000000
[  867.147607] 0064  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.147616] 0084  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.147618]
[  867.147618] LR: 0xffffff8000eeff98:
[  867.147629] ff98  ******** ******** ******** ******** ******** ******** ******** ********
[  867.147639] ffb8  ******** ******** ******** ******** ******** ******** ******** ********
[  867.147650] ffd8  ******** ******** ******** ******** ******** ******** ******** ********
[  867.147659] fff8  ******** ******** a9bf7bfd 910003fd aa1e03e0 d503201f 58000100 95ca7426
[  867.147668] 0018  d2800000 528102e1 72a32ec1 b9000001 a8c17bfd d65f03c0 00ef1024 ffffff80
[  867.147677] 0038  a9bf7bfd 910003fd aa1e03e0 d503201f 58000080 95ca7418 a8c17bfd d65f03c0
[  867.147685] 0058  00ef1038 ffffff80 00000000 00000000 00000000 00000000 00000000 00000000
[  867.147693] 0078  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.147695]
[  867.147695] SP: 0xffffffc00a4ffbc0:
[  867.147705] fbc0  095b7860 ffffff80 00000000 00000000 00ef2050 ffffff80 00000001 00000000
[  867.147713] fbe0  cde6e880 ffffffc0 00000001 00000000 081376d0 ffffff80 0a4ffc40 ffffffc0
[  867.147726] fc00  00ef0018 ffffff80 0a4ffc40 ffffffc0 00ef0024 ffffff80 40000145 00000000
[  867.147734] fc20  ee9ae000 00000040 00012ffb 00000000 00000000 00000080 00000000 00000000
[  867.147743] fc40  0a4ffc50 ffffffc0 080830f8 ffffff80 0a4ffcd0 ffffffc0 0818d2d0 ffffff80
[  867.147765] fc60  00ef2000 ffffff80 095cd000 ffffff80 cde6e8c8 ffffffc0 cdce1140 ffffffc0
[  867.147774] fc80  00000000 00000000 0818d2a4 ffffff80 00ef2000 ffffff80 095cd000 ffffff80
[  867.147782] fca0  cde6e8c8 ffffffc0 095cd000 ffffff80 00000000 00000000 00ef2050 ffffff80
[  867.147785]
[  867.147785] X5: 0xffffffc0f7f24ab8:
[  867.147794] 4ab8  0000003f 00000000 0000003f 00000000 00000000 00000000 00000000 00000000
[  867.147803] 4ad8  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.147811] 4af8  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.147819] 4b18  afbe5356 00000001 00000000 00000000 0810d62c ffffff80 00000001 00000000
[  867.147828] 4b38  00000007 00000000 00000000 00000000 0810dd18 ffffff80 00000000 00000000
[  867.147836] 4b58  00000000 01400000 00000000 0000e293 00000000 00000000 00000000 00000000
[  867.147845] 4b78  00000000 00000000 d591d591 dead4ead ffffffff 00000000 ffffffff ffffffff
[  867.147853] 4b98  00000000 00000000 0008a70b 00000001 0008a701 00000001 0000000d 00000000
[  867.147855]
[  867.147855] X7: 0xffffff8009628030:
[  867.147863] 8030  f26a3900 ffffffc0 00000000 00000000 00000000 00000000 00110000 00000000
[  867.147872] 8050  000f0000 00000000 00000000 00000000 00040000 00000000 00080000 00000000
[  867.147880] 8070  00000000 00000000 00000000 00000000 00000001 00000000 00000000 00000000
[  867.147889] 8090  00000000 00000001 00000000 00000001 00000002 00000001 00000001 00000000
[  867.147897] 80b0  00000000 00000000 0927e623 ffffff80 04e804e8 dead4ead ffffffff 00000000
[  867.147905] 80d0  ffffffff ffffffff f2000000 ffffffc0 00040000 00000000 00000001 00000000
[  867.147914] 80f0  00000000 dead4ead ffffffff 00000000 ffffffff ffffffff 09628108 ffffff80
[  867.147922] 8110  09628108 ffffff80 00000000 00000000 00000000 00000000 00000000 00000000
[  867.147924]
[  867.147924] X8: 0xffffff8008463bbc:
[  867.147933] 3bbc  9400054a aa1303e0 94000554 52800000 a94153f3 f94013f5 a8c37bfd d65f03c0
[  867.147942] 3bdc  f9400413 17fffff6 f9400813 17fffff4 f9400c13 17fffff2 128002a0 17fffff5
[  867.147950] 3bfc  71001c1f 54000161 f9405ce0 f9400c00 b4000140 a9bf7bfd aa0603e2 aa0403e1
[  867.147959] 3c1c  910003fd 940004ce a8c17bfd d65f03c0 128002a0 d65f03c0 12800160 d65f03c0
[  867.147967] 3c3c  a9bb7bfd 7100081f 910003fd a9025bf5 aa0403f6 a90153f3 aa0603f5 a90363f7
[  867.147975] 3c5c  f9405cf3 54000181 f9400660 b4000a20 2a1503e2 aa1603e1 9400047d 52800000
[  867.147984] 3c7c  a94153f3 a9425bf5 a94363f7 a8c57bfd d65f03c0 71000c1f 54000061 f9400a60
[  867.147992] 3c9c  17fffff3 71001c1f 54000061 f9400e60 17ffffef 35000820 51000420 7100041f
[  867.147994]
[  867.147994] X10: 0xffffff80097bfa1f:
[  867.148003] fa1c  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148011] fa3c  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148020] fa5c  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148028] fa7c  00000000 00000000 00000000 00000000 00000000 00000001 00000000 3820205b
[  867.148037] fa9c  312e3736 39343734 78205d31 203a3532 30303030 30303030 30303030 31303030
[  867.148045] fabc  5d3e3420 20726c20 3c5b203a 66666666 30386666 66653030 38313030 70205d3e
[  867.148054] fadc  74617473 34203a65 30303030 0a353431 30303030 0a303030 742f0a67 296d0a78
[  867.148062] fafc  3028202c 0a297320 3331200a 3a34353a 76203334 69737265 37206e6f 2e35332e
[  867.148071] fb1c  2e343831 35722e31 32412820 61745320 6e6f6974 5032502f 57462029 30204449
[  867.148074]
[  867.148074] X16: 0xffffff800813b184:
[  867.148083] b184  fa413002 9a9f87e2 b4000202 aa1303e2 aa1403e1 aa1503e0 940e73e9 b5000220
[  867.148093] b1a4  943672e0 8b1302b5 8b130294 eb1302f7 54fffde1 52800002 aa1603e1 910163a0
[  867.148101] b1c4  97fff7ff 17ffffc6 aa1303e2 52800001 aa1503e0 940e775a aa1303e0 17fffff0
[  867.148110] b1e4  f9402fa0 94021fc6 128001a0 17ffffbc 128000e0 17ffffba 12800160 17ffffb8
[  867.148118] b204  a9b67bfd 910003fd a90153f3 f90013f5 aa0003f5 aa1e03e0 aa0103f4 aa0203f3
[  867.148127] b224  d503201f a903ffbf a904ffbf a905ffbf a906ffbf a907ffbf a908ffbf f9004fbf
[  867.148135] b244  97ffefb2 340000c0 93407c00 a94153f3 f94013f5 a8ca7bfd d65f03c0 f000b220
[  867.148143] b264  913d0000 910aa000 79404401 361000e1 d00088a1 2a1303e4 aa1403e3 2a1503e2
[  867.148146]
[  867.148146] X18: 0xffffff80897bfa17:
[  867.148157] fa14  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148167] fa34  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148178] fa54  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148189] fa74  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148199] fa94  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148210] fab4  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148221] fad4  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148232] faf4  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148243] fb14  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148244]
[  867.148244] X19: 0xffffff8000eeff80:
[  867.148256] ff80  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148271] ffa0  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148282] ffc0  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148293] ffe0  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148303] 0000  a9bf7bfd 910003fd aa1e03e0 d503201f 58000100 95ca7426 d2800000 528102e1
[  867.148311] 0020  72a32ec1 b9000001 a8c17bfd d65f03c0 00ef1024 ffffff80 a9bf7bfd 910003fd
[  867.148320] 0040  aa1e03e0 d503201f 58000080 95ca7418 a8c17bfd d65f03c0 00ef1038 ffffff80
[  867.148328] 0060  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148330]
[  867.148330] X20: 0xffffff80095b77e0:
[  867.148338] 77e0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148346] 7800  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148355] 7820  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148363] 7840  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148372] 7860  095b7860 ffffff80 095b7860 ffffff80 00000001 00000000 00005dc0 00000000
[  867.148380] 7880  00000009 756e694c 00000078 00000000 00000000 00000000 00000000 00000000
[  867.148388] 78a0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148397] 78c0  00000000 72696600 796c6665 00000000 00000000 00000000 00000000 00000000
[  867.148398]
[  867.148398] X21: 0xffffffc0cdce1040:
[  867.148407] 1040  746f6e2e 6e672e65 75622e75 2d646c69 00006469 dead0000 00000200 dead0000
[  867.148415] 1060  00000001 00000000 00000000 00000000 00000000 00000000 055aab56 00000000
[  867.148424] 1080  cdce1bc0 ffffffc0 cde6d909 ffffffc0 cde6d888 ffffffc0 cdce1bc8 ffffffc0
[  867.148433] 10a0  00000000 00000000 000003dd 6c62010e 6c6b6361 2e747369 666e6f63 00000000
[  867.148441] 10c0  cdce1080 ffffffc0 6d656473 6f5b206f 5f73706f 75646f6d 005d656c 00000000
[  867.148449] 10e0  00000000 00000000 0000000f 2e2e0202 00000000 00000000 00000000 00000000
[  867.148458] 1100  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148466] 1120  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148468]
[  867.148468] X22: 0xffffff80095b77e0:
[  867.148476] 77e0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148484] 7800  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148493] 7820  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148501] 7840  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148510] 7860  095b7860 ffffff80 095b7860 ffffff80 00000001 00000000 00005dc0 00000000
[  867.148518] 7880  00000009 756e694c 00000078 00000000 00000000 00000000 00000000 00000000
[  867.148526] 78a0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148535] 78c0  00000000 72696600 796c6665 00000000 00000000 00000000 00000000 00000000
[  867.148536]
[  867.148536] X24: 0xffffff8000ef1fd0:
[  867.148545] 1fd0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148553] 1ff0  00000000 00000000 00000000 00000000 00000001 00000000 095cd3a0 ffffff80
[  867.148562] 2010  095cd3a0 ffffff80 73706f6f 646f6d5f 00656c75 00000000 00000000 00000000
[  867.148570] 2030  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148578] 2050  f089a080 ffffffc0 f26add00 ffffffc0 f2117e88 ffffffc0 f26add28 ffffffc0
[  867.148588] 2070  f26add00 ffffffc0 095c4c08 ffffff80 dbb66f78 ffffffc0 00000003 00000007
[  867.148596] 2090  00ef2000 ffffff80 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148605] 20b0  f2f99c00 ffffffc0 00000000 00000000 00000000 00000000 f089ab40 ffffffc0
[  867.148606]
[  867.148606] X26: 0xffffffc0cde6e800:
[  867.148615] e800  00000001 00000000 d11d71a8 ffffffc0 00000000 00000000 00000000 00000000
[  867.148623] e820  cf2e6030 ffffffc0 00000000 00000000 0000046d 00000000 095c42c8 ffffff80
[  867.148632] e840  00000000 00000000 f7ec5e68 ffffffc0 00000000 00000000 00000000 00000000
[  867.148640] e860  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148649] e880  f106a880 ffffffc0 00000001 00000000 f089aa40 ffffffc0 00000124 00000000
[  867.148657] e8a0  00000024 00000000 00ef1000 ffffff80 081375b0 ffffff80 00000000 00000000
[  867.148665] e8c0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148674] e8e0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148675]
[  867.148675] X28: 0xffffff8008137650:
[  867.148684] 7650  a90153f3 aa0103f4 aa0203f3 aa1e03e0 d503201f f0008f21 913a1c21 f9402280
[  867.148693] 7670  b941d802 aa1303e0 940eb71d 93407c00 a94153f3 a8c27bfd d65f03c0 a9be7bfd
[  867.148701] 7690  910003fd a90153f3 aa0103f4 aa0203f3 aa1e03e0 d503201f f0008f21 913a1c21
[  867.148710] 76b0  f9402280 b9418802 aa1303e0 940eb70c 93407c00 a94153f3 a8c27bfd d65f03c0
[  867.148718] 76d0  a9be7bfd 910003fd a90153f3 aa0003f4 aa0203f3 aa1e03e0 d503201f aa1303e0
[  867.148727] 76f0  b0008b61 f9402282 91068021 940eb6fc 93407c00 a94153f3 a8c27bfd d65f03c0
[  867.148735] 7710  a9be7bfd 910003fd a90153f3 aa0003f3 aa0103f4 aa1e03e0 d503201f 52801801
[  867.148743] 7730  aa1403e0 72a04801 9401c11a f9006260 a94153f3 a8c27bfd d65f03c0 a9be7bfd
[  867.148745]
[  867.148745] X29: 0xffffffc00a4ffbc0:
[  867.148754] fbc0  095b7860 ffffff80 00000000 00000000 00ef2050 ffffff80 00000001 00000000
[  867.148763] fbe0  cde6e880 ffffffc0 00000001 00000000 081376d0 ffffff80 0a4ffc40 ffffffc0
[  867.148771] fc00  00ef0018 ffffff80 0a4ffc40 ffffffc0 00ef0024 ffffff80 40000145 00000000
[  867.148780] fc20  ee9ae000 00000040 00012ffb 00000000 00000000 00000080 00000000 00000000
[  867.148790] fc40  0a4ffc50 ffffffc0 080830f8 ffffff80 0a4ffcd0 ffffffc0 0818d2d0 ffffff80
[  867.148798] fc60  00ef2000 ffffff80 095cd000 ffffff80 cde6e8c8 ffffffc0 cdce1140 ffffffc0
[  867.148807] fc80  00000000 00000000 0818d2a4 ffffff80 00ef2000 ffffff80 095cd000 ffffff80
[  867.148815] fca0  cde6e8c8 ffffffc0 095cd000 ffffff80 00000000 00000000 00ef2050 ffffff80
[  867.148816]
[  867.148820] Process insmod (pid: 1163, stack limit = 0xffffffc00a4fc000)
[  867.148822] Stack: (0xffffffc00a4ffc40 to 0xffffffc00a500000)
[  867.148826] fc40: ffffffc00a4ffc50 ffffff80080830f8 ffffffc00a4ffcd0 ffffff800818d2d0
[  867.148829] fc60: ffffff8000ef2000 ffffff80095cd000 ffffffc0cde6e8c8 ffffffc0cdce1140
[  867.148832] fc80: 0000000000000000 ffffff800818d2a4 ffffff8000ef2000 ffffff80095cd000
[  867.148834] fca0: ffffffc0cde6e8c8 ffffff80095cd000 0000000000000000 ffffff8000ef2050
[  867.148837] fcc0: 0000000000000001 ffffffc0cde6e880 ffffffc00a4ffd00 ffffff800813ab5c
[  867.148840] fce0: ffffff8000ef2000 ffffffc00a4ffe58 ffffffc0cde6e8c8 ffffff80095cd000
[  867.148843] fd00: ffffffc00a4ffe20 ffffff800813b2b4 0000000000000000 00000055736b60f0
[  867.148846] fd20: 0000000000000003 0000007fb096c8c4 0000000040000000 0000000000000015
[  867.148849] fd40: 000000000000011d 0000000000000111 ffffff8008ef2000 ffffffc0cdc44380
[  867.148851] fd60: 0000000000000000 000000000002c098 ffffffc00a4ffe20 ffffff8008f00000
[  867.148854] fd80: 0000000000000000 00000055736b60f0 ffffffc000000064 ffffff8000000072
[  867.148857] fda0: ffffff800000006e ffffff800000003f ffffff8000000124 00000000024000c0
[  867.148860] fdc0: ffff81b400000030 000003e800000001 00000000000003e8 000000000002c098
[  867.148862] fde0: 00000000633eccfc 0000000000000000 0000000000000000 0000000000000000
[  867.148865] fe00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[  867.148868] fe20: 0000000000000000 ffffff8008082f70 0000000000000000 00000040ee9ae000
[  867.148871] fe40: ffffffffffffffff 0000000000000001 0000000000000002 ffffff800bea0000
[  867.148874] fe60: 000000000002c098 ffffff800becb9d8 ffffff800becb8d0 ffffff800beb7748
[  867.148876] fe80: 0000000000003000 00000000000030d8 0000000000000000 0000000000000000
[  867.148879] fea0: 0000000000000478 0000001a00000019 0000000000000009 0000000000000004
[  867.148882] fec0: 0000000000000003 00000055736b60f0 0000000000000000 0000000000000003
[  867.148884] fee0: 0000000000000000 0000000000000218 0000000000000001 0000000000000001
[  867.148887] ff00: 0000000000000111 0000000000000003 0000000200000002 0000000000000000
[  867.148890] ff20: 00000000000010f0 0000000000000000 0000000000000000 0000000000000040
[  867.148892] ff40: 00000055736cddb0 0000007fb096c8a0 0000000000000000 0000005585e6b600
[  867.148895] ff60: 00000055736b60f0 0000000000000000 0000000000000000 0000005585e6b5d0
[  867.148898] ff80: 00000055736b2ef8 0000000000000000 0000000000000000 0000000000000000
[  867.148901] ffa0: 0000000000000000 0000007fdbea3bd0 00000055736abdc0 0000007fdbea3bd0
[  867.148903] ffc0: 0000007fb096c8c4 0000000040000000 0000000000000003 0000000000000111
[  867.148906] ffe0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[  867.148907] Call trace:
[  867.148911] Exception stack(0xffffffc00a4ffa70 to 0xffffffc00a4ffba0)
[  867.148913] fa60:                                   ffffff8000ef0000 0000008000000000
[  867.148916] fa80: ffffffc00a4ffc40 ffffff8000ef0024 ffffff80097c02f8 0000000000000002
[  867.148918] faa0: ffffffc00a4ffac0 000000020001b57c 0000000000000000 0000000100000000
[  867.148921] fac0: ffffffc00a4ffb60 ffffff800810d674 ffffffc00a4ffbc0 ffffff8000ef1024
[  867.148924] fae0: ffffffc0cdce10c0 ffffff80095b7860 0000000000000000 ffffff8000ef2050
[  867.148927] fb00: 0000000000000001 ffffffc0cde6e880 0000000000000000 0000000019760817
[  867.148929] fb20: 0000000000000007 0000000000000007 0000000000000001 ffffffc0f7f24b38
[  867.148932] fb40: 0000000000000022 ffffff80096280b0 ffffff8008463c3c 0000000005f5e0ff
[  867.148935] fb60: ffffff80097bfa9f 00000000fffffffe 0000000000000030 000000000000000a
[  867.148937] fb80: 00000000000224d6 0000000000000000 ffffff800813b204 0000007fb096c8a0
[  867.148944] [<ffffff8000ef0024>] init_oopsdemo+0x24/0x38 [oops_module]
[  867.148953] [<ffffff80080830f8>] do_one_initcall+0x78/0x194
[  867.148958] [<ffffff800818d2d0>] do_init_module+0x64/0x1c0
[  867.148962] [<ffffff800813ab5c>] load_module+0x199c/0x1ed0
[  867.148964] [<ffffff800813b2b4>] SyS_finit_module+0xb0/0xbc
[  867.148968] [<ffffff8008082f70>] el0_svc_naked+0x24/0x28
[  867.148972] Code: 95ca7426 d2800000 528102e1 72a32ec1 (b9000001)
[  867.148975] ---[ end trace 1983a52768236533 ]---

[/cc]

[cc lang="cpp"]

[  867.140514] Unable to handle kernel NULL pointer dereference at virtual address 00000000

[/cc]

这里能够简要的告诉是什么问题触发了oops,显然是由于访问非法地址00000000异常。如果是由代码直接调用BUG()/BUG_ON()一类的,还能给出源代码中触发的行号。

[cc lang="cpp"]

[  867.141279] pgd = ffffffc0f0a65000
[  867.141582] [00000000] *pgd=0000000000000000, *pud=0000000000000000

[/cc]

pgd,pud试图访问的地址的页表信息,本例中为0。

[cc lang="cpp"]

[  867.142164] Internal error: Oops: 96000045 [#1] SMP

[/cc]

96000045表示错误码。后面[]内的数值是与页面有关的oops信息被显示的次数。之后显示内核的重要特性SMP和PREEMPT被显示的配置情况。这条信息所在的内核启用了SMP支持,所以只显示SMP。

96000045这种错误码我也是第一次见,内核中也没找到。一般见的最多的就是001,002这种形式的?有大佬知道原因的可以评论下。

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

[cc lang="cpp"]

[  867.142592] Modules linked in: oops_module(O+) [last unloaded: hello_module]

[/cc]

Modules linked in为加载了的模块列表,hello_module为上次加载的模块。

[cc lang="cpp"]

[  867.143006] CPU: 4 PID: 1163 Comm: insmod Tainted: G           O    4.4.194+ #7
[  867.143649] Hardware name: Firefly-RK3399 Board (Linux Opensource) (DT)
[  867.144236] task: ffffffc0cdc44380 task.stack: ffffffc00a4fc000

[/cc]

CPU后的数字是错误所在逻辑CPU的编号,PID表示正在运行的进程ID1511,内核污染原因(G),内核版本( 4.4.194)。

内核污染原因包括私有驱动加载(P),模块强制加载(F),模块强制卸载(R),机器检查异常发生(M),检测到错误页(B)等。

如果涉及到了某项原因,就会显示为Tainted: G PF R这样。如果不存在问题,就会显示为Not Tainted。

其中Tainted的表示可以从内核中 kernel/panic.c 中找到:

Tainted 描述
‘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.
‘F’ if any module was force loaded by “insmod -f”.
‘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.
‘R’ if a module was force unloaded by “rmmod -f”.
‘M’ if any processor has reported a Machine Check Exception.
‘B’ if a page-release function has found a bad page reference or some unexpected page flags.
‘U’ if a user or user application specifically requested that the Tainted flag be set.
‘D’ if the kernel has died recently, i.e. there was an OOPS or BUG.
‘W’ if a warning has previously been issued by the kernel.
‘C’ if a staging module / driver has been loaded.
‘I’ if the kernel is working around a sever bug in the platform’s firmware (BIOS or similar).

Hardware  name 表示硬件平台的名称。

task 表示当前进程的地址,  task.stack 表示当前进程栈的地址。

[cc lang="cpp"]
[  867.144761] PC is at init_oopsdemo+0x24/0x38 [oops_module]
[  867.145247] LR is at init_oopsdemo+0x18/0x38 [oops_module]
[  867.145732] pc : [<ffffff8000ef0024>] lr : [<ffffff8000ef0018>] pstate: 40000145
[  867.146386] sp : ffffffc00a4ffc40
[/cc]

init_oopsdemo+0x24/0x38[oops_module] 表示错误发生的地址是oops_module中的 init_oopsdemo 函数的第44个字节, 0x38 表示 init_oopsdemo 函数的大小。
第3行,第4行分别是PC,LR,SP寄存器的具体地址。

[cc lang=c]
[  867.146688] x29: ffffffc00a4ffc40 x28: ffffff80081376d0
[  867.147178] x27: 0000000000000001 x26: ffffffc0cde6e880
[  867.147491] x25: 0000000000000001 x24: ffffff8000ef2050
[  867.147495] x23: 0000000000000000 x22: ffffff80095b7860
[  867.147498] x21: ffffffc0cdce10c0 x20: ffffff80095b7860
[  867.147501] x19: ffffff8000ef0000 x18: ffffff80897bfa97
[  867.147504] x17: 0000007fb096c8a0 x16: ffffff800813b204
[  867.147508] x15: 0000000000000000 x14: 00000000000224d6
[  867.147511] x13: 000000000000000a x12: 0000000000000030
[  867.147515] x11: 00000000fffffffe x10: ffffff80097bfa9f
[  867.147518] x9 : 0000000005f5e0ff x8 : ffffff8008463c3c
[  867.147522] x7 : ffffff80096280b0 x6 : 0000000000000022
[  867.147525] x5 : ffffffc0f7f24b38 x4 : 0000000000000001
[  867.147528] x3 : 0000000000000007 x2 : 0000000000000007
[  867.147534] x1 : 0000000019760817 x0 : 0000000000000000
[  867.147536]
[  867.147536] PC: 0xffffff8000eeffa4:
[  867.147550] ffa4  ******** ******** ******** ******** ******** ******** ******** ********
[  867.147561] ffc4  ******** ******** ******** ******** ******** ******** ******** ********
[  867.147572] ffe4  ******** ******** ******** ******** ******** ******** ******** a9bf7bfd
[  867.147581] 0004  910003fd aa1e03e0 d503201f 58000100 95ca7426 d2800000 528102e1 72a32ec1
[  867.147590] 0024  b9000001 a8c17bfd d65f03c0 00ef1024 ffffff80 a9bf7bfd 910003fd aa1e03e0
[  867.147599] 0044  d503201f 58000080 95ca7418 a8c17bfd d65f03c0 00ef1038 ffffff80 00000000
[  867.147607] 0064  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.147616] 0084  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.147618]
[  867.147618] LR: 0xffffff8000eeff98:
[  867.147629] ff98  ******** ******** ******** ******** ******** ******** ******** ********
[  867.147639] ffb8  ******** ******** ******** ******** ******** ******** ******** ********
[  867.147650] ffd8  ******** ******** ******** ******** ******** ******** ******** ********
[  867.147659] fff8  ******** ******** a9bf7bfd 910003fd aa1e03e0 d503201f 58000100 95ca7426
[  867.147668] 0018  d2800000 528102e1 72a32ec1 b9000001 a8c17bfd d65f03c0 00ef1024 ffffff80
[  867.147677] 0038  a9bf7bfd 910003fd aa1e03e0 d503201f 58000080 95ca7418 a8c17bfd d65f03c0
[  867.147685] 0058  00ef1038 ffffff80 00000000 00000000 00000000 00000000 00000000 00000000
[  867.147693] 0078  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.147695]
[  867.147695] SP: 0xffffffc00a4ffbc0:
[  867.147705] fbc0  095b7860 ffffff80 00000000 00000000 00ef2050 ffffff80 00000001 00000000
[  867.147713] fbe0  cde6e880 ffffffc0 00000001 00000000 081376d0 ffffff80 0a4ffc40 ffffffc0
[  867.147726] fc00  00ef0018 ffffff80 0a4ffc40 ffffffc0 00ef0024 ffffff80 40000145 00000000
[  867.147734] fc20  ee9ae000 00000040 00012ffb 00000000 00000000 00000080 00000000 00000000
[  867.147743] fc40  0a4ffc50 ffffffc0 080830f8 ffffff80 0a4ffcd0 ffffffc0 0818d2d0 ffffff80
[  867.147765] fc60  00ef2000 ffffff80 095cd000 ffffff80 cde6e8c8 ffffffc0 cdce1140 ffffffc0
[  867.147774] fc80  00000000 00000000 0818d2a4 ffffff80 00ef2000 ffffff80 095cd000 ffffff80
[  867.147782] fca0  cde6e8c8 ffffffc0 095cd000 ffffff80 00000000 00000000 00ef2050 ffffff80
[  867.147785]
[  867.147785] X5: 0xffffffc0f7f24ab8:
[  867.147794] 4ab8  0000003f 00000000 0000003f 00000000 00000000 00000000 00000000 00000000
[  867.147803] 4ad8  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.147811] 4af8  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.147819] 4b18  afbe5356 00000001 00000000 00000000 0810d62c ffffff80 00000001 00000000
[  867.147828] 4b38  00000007 00000000 00000000 00000000 0810dd18 ffffff80 00000000 00000000
[  867.147836] 4b58  00000000 01400000 00000000 0000e293 00000000 00000000 00000000 00000000
[  867.147845] 4b78  00000000 00000000 d591d591 dead4ead ffffffff 00000000 ffffffff ffffffff
[  867.147853] 4b98  00000000 00000000 0008a70b 00000001 0008a701 00000001 0000000d 00000000
[  867.147855]
[  867.147855] X7: 0xffffff8009628030:
[  867.147863] 8030  f26a3900 ffffffc0 00000000 00000000 00000000 00000000 00110000 00000000
[  867.147872] 8050  000f0000 00000000 00000000 00000000 00040000 00000000 00080000 00000000
[  867.147880] 8070  00000000 00000000 00000000 00000000 00000001 00000000 00000000 00000000
[  867.147889] 8090  00000000 00000001 00000000 00000001 00000002 00000001 00000001 00000000
[  867.147897] 80b0  00000000 00000000 0927e623 ffffff80 04e804e8 dead4ead ffffffff 00000000
[  867.147905] 80d0  ffffffff ffffffff f2000000 ffffffc0 00040000 00000000 00000001 00000000
[  867.147914] 80f0  00000000 dead4ead ffffffff 00000000 ffffffff ffffffff 09628108 ffffff80
[  867.147922] 8110  09628108 ffffff80 00000000 00000000 00000000 00000000 00000000 00000000
[  867.147924]
[  867.147924] X8: 0xffffff8008463bbc:
[  867.147933] 3bbc  9400054a aa1303e0 94000554 52800000 a94153f3 f94013f5 a8c37bfd d65f03c0
[  867.147942] 3bdc  f9400413 17fffff6 f9400813 17fffff4 f9400c13 17fffff2 128002a0 17fffff5
[  867.147950] 3bfc  71001c1f 54000161 f9405ce0 f9400c00 b4000140 a9bf7bfd aa0603e2 aa0403e1
[  867.147959] 3c1c  910003fd 940004ce a8c17bfd d65f03c0 128002a0 d65f03c0 12800160 d65f03c0
[  867.147967] 3c3c  a9bb7bfd 7100081f 910003fd a9025bf5 aa0403f6 a90153f3 aa0603f5 a90363f7
[  867.147975] 3c5c  f9405cf3 54000181 f9400660 b4000a20 2a1503e2 aa1603e1 9400047d 52800000
[  867.147984] 3c7c  a94153f3 a9425bf5 a94363f7 a8c57bfd d65f03c0 71000c1f 54000061 f9400a60
[  867.147992] 3c9c  17fffff3 71001c1f 54000061 f9400e60 17ffffef 35000820 51000420 7100041f
[  867.147994]
[  867.147994] X10: 0xffffff80097bfa1f:
[  867.148003] fa1c  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148011] fa3c  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148020] fa5c  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148028] fa7c  00000000 00000000 00000000 00000000 00000000 00000001 00000000 3820205b
[  867.148037] fa9c  312e3736 39343734 78205d31 203a3532 30303030 30303030 30303030 31303030
[  867.148045] fabc  5d3e3420 20726c20 3c5b203a 66666666 30386666 66653030 38313030 70205d3e
[  867.148054] fadc  74617473 34203a65 30303030 0a353431 30303030 0a303030 742f0a67 296d0a78
[  867.148062] fafc  3028202c 0a297320 3331200a 3a34353a 76203334 69737265 37206e6f 2e35332e
[  867.148071] fb1c  2e343831 35722e31 32412820 61745320 6e6f6974 5032502f 57462029 30204449
[  867.148074]
[  867.148074] X16: 0xffffff800813b184:
[  867.148083] b184  fa413002 9a9f87e2 b4000202 aa1303e2 aa1403e1 aa1503e0 940e73e9 b5000220
[  867.148093] b1a4  943672e0 8b1302b5 8b130294 eb1302f7 54fffde1 52800002 aa1603e1 910163a0
[  867.148101] b1c4  97fff7ff 17ffffc6 aa1303e2 52800001 aa1503e0 940e775a aa1303e0 17fffff0
[  867.148110] b1e4  f9402fa0 94021fc6 128001a0 17ffffbc 128000e0 17ffffba 12800160 17ffffb8
[  867.148118] b204  a9b67bfd 910003fd a90153f3 f90013f5 aa0003f5 aa1e03e0 aa0103f4 aa0203f3
[  867.148127] b224  d503201f a903ffbf a904ffbf a905ffbf a906ffbf a907ffbf a908ffbf f9004fbf
[  867.148135] b244  97ffefb2 340000c0 93407c00 a94153f3 f94013f5 a8ca7bfd d65f03c0 f000b220
[  867.148143] b264  913d0000 910aa000 79404401 361000e1 d00088a1 2a1303e4 aa1403e3 2a1503e2
[  867.148146]
[  867.148146] X18: 0xffffff80897bfa17:
[  867.148157] fa14  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148167] fa34  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148178] fa54  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148189] fa74  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148199] fa94  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148210] fab4  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148221] fad4  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148232] faf4  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148243] fb14  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148244]
[  867.148244] X19: 0xffffff8000eeff80:
[  867.148256] ff80  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148271] ffa0  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148282] ffc0  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148293] ffe0  ******** ******** ******** ******** ******** ******** ******** ********
[  867.148303] 0000  a9bf7bfd 910003fd aa1e03e0 d503201f 58000100 95ca7426 d2800000 528102e1
[  867.148311] 0020  72a32ec1 b9000001 a8c17bfd d65f03c0 00ef1024 ffffff80 a9bf7bfd 910003fd
[  867.148320] 0040  aa1e03e0 d503201f 58000080 95ca7418 a8c17bfd d65f03c0 00ef1038 ffffff80
[  867.148328] 0060  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148330]
[  867.148330] X20: 0xffffff80095b77e0:
[  867.148338] 77e0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148346] 7800  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148355] 7820  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148363] 7840  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148372] 7860  095b7860 ffffff80 095b7860 ffffff80 00000001 00000000 00005dc0 00000000
[  867.148380] 7880  00000009 756e694c 00000078 00000000 00000000 00000000 00000000 00000000
[  867.148388] 78a0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148397] 78c0  00000000 72696600 796c6665 00000000 00000000 00000000 00000000 00000000
[  867.148398]
[  867.148398] X21: 0xffffffc0cdce1040:
[  867.148407] 1040  746f6e2e 6e672e65 75622e75 2d646c69 00006469 dead0000 00000200 dead0000
[  867.148415] 1060  00000001 00000000 00000000 00000000 00000000 00000000 055aab56 00000000
[  867.148424] 1080  cdce1bc0 ffffffc0 cde6d909 ffffffc0 cde6d888 ffffffc0 cdce1bc8 ffffffc0
[  867.148433] 10a0  00000000 00000000 000003dd 6c62010e 6c6b6361 2e747369 666e6f63 00000000
[  867.148441] 10c0  cdce1080 ffffffc0 6d656473 6f5b206f 5f73706f 75646f6d 005d656c 00000000
[  867.148449] 10e0  00000000 00000000 0000000f 2e2e0202 00000000 00000000 00000000 00000000
[  867.148458] 1100  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148466] 1120  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148468]
[  867.148468] X22: 0xffffff80095b77e0:
[  867.148476] 77e0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148484] 7800  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148493] 7820  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148501] 7840  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148510] 7860  095b7860 ffffff80 095b7860 ffffff80 00000001 00000000 00005dc0 00000000
[  867.148518] 7880  00000009 756e694c 00000078 00000000 00000000 00000000 00000000 00000000
[  867.148526] 78a0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148535] 78c0  00000000 72696600 796c6665 00000000 00000000 00000000 00000000 00000000
[  867.148536]
[  867.148536] X24: 0xffffff8000ef1fd0:
[  867.148545] 1fd0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148553] 1ff0  00000000 00000000 00000000 00000000 00000001 00000000 095cd3a0 ffffff80
[  867.148562] 2010  095cd3a0 ffffff80 73706f6f 646f6d5f 00656c75 00000000 00000000 00000000
[  867.148570] 2030  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148578] 2050  f089a080 ffffffc0 f26add00 ffffffc0 f2117e88 ffffffc0 f26add28 ffffffc0
[  867.148588] 2070  f26add00 ffffffc0 095c4c08 ffffff80 dbb66f78 ffffffc0 00000003 00000007
[  867.148596] 2090  00ef2000 ffffff80 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148605] 20b0  f2f99c00 ffffffc0 00000000 00000000 00000000 00000000 f089ab40 ffffffc0
[  867.148606]
[  867.148606] X26: 0xffffffc0cde6e800:
[  867.148615] e800  00000001 00000000 d11d71a8 ffffffc0 00000000 00000000 00000000 00000000
[  867.148623] e820  cf2e6030 ffffffc0 00000000 00000000 0000046d 00000000 095c42c8 ffffff80
[  867.148632] e840  00000000 00000000 f7ec5e68 ffffffc0 00000000 00000000 00000000 00000000
[  867.148640] e860  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148649] e880  f106a880 ffffffc0 00000001 00000000 f089aa40 ffffffc0 00000124 00000000
[  867.148657] e8a0  00000024 00000000 00ef1000 ffffff80 081375b0 ffffff80 00000000 00000000
[  867.148665] e8c0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148674] e8e0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  867.148675]
[  867.148675] X28: 0xffffff8008137650:
[  867.148684] 7650  a90153f3 aa0103f4 aa0203f3 aa1e03e0 d503201f f0008f21 913a1c21 f9402280
[  867.148693] 7670  b941d802 aa1303e0 940eb71d 93407c00 a94153f3 a8c27bfd d65f03c0 a9be7bfd
[  867.148701] 7690  910003fd a90153f3 aa0103f4 aa0203f3 aa1e03e0 d503201f f0008f21 913a1c21
[  867.148710] 76b0  f9402280 b9418802 aa1303e0 940eb70c 93407c00 a94153f3 a8c27bfd d65f03c0
[  867.148718] 76d0  a9be7bfd 910003fd a90153f3 aa0003f4 aa0203f3 aa1e03e0 d503201f aa1303e0
[  867.148727] 76f0  b0008b61 f9402282 91068021 940eb6fc 93407c00 a94153f3 a8c27bfd d65f03c0
[  867.148735] 7710  a9be7bfd 910003fd a90153f3 aa0003f3 aa0103f4 aa1e03e0 d503201f 52801801
[  867.148743] 7730  aa1403e0 72a04801 9401c11a f9006260 a94153f3 a8c27bfd d65f03c0 a9be7bfd
[  867.148745]
[  867.148745] X29: 0xffffffc00a4ffbc0:
[  867.148754] fbc0  095b7860 ffffff80 00000000 00000000 00ef2050 ffffff80 00000001 00000000
[  867.148763] fbe0  cde6e880 ffffffc0 00000001 00000000 081376d0 ffffff80 0a4ffc40 ffffffc0
[  867.148771] fc00  00ef0018 ffffff80 0a4ffc40 ffffffc0 00ef0024 ffffff80 40000145 00000000
[  867.148780] fc20  ee9ae000 00000040 00012ffb 00000000 00000000 00000080 00000000 00000000
[  867.148790] fc40  0a4ffc50 ffffffc0 080830f8 ffffff80 0a4ffcd0 ffffffc0 0818d2d0 ffffff80
[  867.148798] fc60  00ef2000 ffffff80 095cd000 ffffff80 cde6e8c8 ffffffc0 cdce1140 ffffffc0
[  867.148807] fc80  00000000 00000000 0818d2a4 ffffff80 00ef2000 ffffff80 095cd000 ffffff80
[  867.148815] fca0  cde6e8c8 ffffffc0 095cd000 ffffff80 00000000 00000000 00ef2050 ffffff80
[  867.148816]

[/cc]

上面打印出的这些都是异常发生时寄存器的值。

[cc lang="cpp"]
[  867.148820] Process insmod (pid: 1163, stack limit = 0xffffffc00a4fc000)
[  867.148822] Stack: (0xffffffc00a4ffc40 to 0xffffffc00a500000)
[  867.148826] fc40: ffffffc00a4ffc50 ffffff80080830f8 ffffffc00a4ffcd0 ffffff800818d2d0
[  867.148829] fc60: ffffff8000ef2000 ffffff80095cd000 ffffffc0cde6e8c8 ffffffc0cdce1140
[  867.148832] fc80: 0000000000000000 ffffff800818d2a4 ffffff8000ef2000 ffffff80095cd000
[  867.148834] fca0: ffffffc0cde6e8c8 ffffff80095cd000 0000000000000000 ffffff8000ef2050
[  867.148837] fcc0: 0000000000000001 ffffffc0cde6e880 ffffffc00a4ffd00 ffffff800813ab5c
[  867.148840] fce0: ffffff8000ef2000 ffffffc00a4ffe58 ffffffc0cde6e8c8 ffffff80095cd000
[  867.148843] fd00: ffffffc00a4ffe20 ffffff800813b2b4 0000000000000000 00000055736b60f0
[  867.148846] fd20: 0000000000000003 0000007fb096c8c4 0000000040000000 0000000000000015
[  867.148849] fd40: 000000000000011d 0000000000000111 ffffff8008ef2000 ffffffc0cdc44380
[  867.148851] fd60: 0000000000000000 000000000002c098 ffffffc00a4ffe20 ffffff8008f00000
[  867.148854] fd80: 0000000000000000 00000055736b60f0 ffffffc000000064 ffffff8000000072
[  867.148857] fda0: ffffff800000006e ffffff800000003f ffffff8000000124 00000000024000c0
[  867.148860] fdc0: ffff81b400000030 000003e800000001 00000000000003e8 000000000002c098
[  867.148862] fde0: 00000000633eccfc 0000000000000000 0000000000000000 0000000000000000
[  867.148865] fe00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[  867.148868] fe20: 0000000000000000 ffffff8008082f70 0000000000000000 00000040ee9ae000
[  867.148871] fe40: ffffffffffffffff 0000000000000001 0000000000000002 ffffff800bea0000
[  867.148874] fe60: 000000000002c098 ffffff800becb9d8 ffffff800becb8d0 ffffff800beb7748
[  867.148876] fe80: 0000000000003000 00000000000030d8 0000000000000000 0000000000000000
[  867.148879] fea0: 0000000000000478 0000001a00000019 0000000000000009 0000000000000004
[  867.148882] fec0: 0000000000000003 00000055736b60f0 0000000000000000 0000000000000003
[  867.148884] fee0: 0000000000000000 0000000000000218 0000000000000001 0000000000000001
[  867.148887] ff00: 0000000000000111 0000000000000003 0000000200000002 0000000000000000
[  867.148890] ff20: 00000000000010f0 0000000000000000 0000000000000000 0000000000000040
[  867.148892] ff40: 00000055736cddb0 0000007fb096c8a0 0000000000000000 0000005585e6b600
[  867.148895] ff60: 00000055736b60f0 0000000000000000 0000000000000000 0000005585e6b5d0
[  867.148898] ff80: 00000055736b2ef8 0000000000000000 0000000000000000 0000000000000000
[  867.148901] ffa0: 0000000000000000 0000007fdbea3bd0 00000055736abdc0 0000007fdbea3bd0
[  867.148903] ffc0: 0000007fb096c8c4 0000000040000000 0000000000000003 0000000000000111
[  867.148906] ffe0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[/cc]
stack limit显示的大小为kstack内核选项指定的大小。Stack 是栈开头部分的值。
[cc lang="cpp"]
[  867.148907] Call trace:
[  867.148911] Exception stack(0xffffffc00a4ffa70 to 0xffffffc00a4ffba0)
[  867.148913] fa60:                                   ffffff8000ef0000 0000008000000000
[  867.148916] fa80: ffffffc00a4ffc40 ffffff8000ef0024 ffffff80097c02f8 0000000000000002
[  867.148918] faa0: ffffffc00a4ffac0 000000020001b57c 0000000000000000 0000000100000000
[  867.148921] fac0: ffffffc00a4ffb60 ffffff800810d674 ffffffc00a4ffbc0 ffffff8000ef1024
[  867.148924] fae0: ffffffc0cdce10c0 ffffff80095b7860 0000000000000000 ffffff8000ef2050
[  867.148927] fb00: 0000000000000001 ffffffc0cde6e880 0000000000000000 0000000019760817
[  867.148929] fb20: 0000000000000007 0000000000000007 0000000000000001 ffffffc0f7f24b38
[  867.148932] fb40: 0000000000000022 ffffff80096280b0 ffffff8008463c3c 0000000005f5e0ff
[  867.148935] fb60: ffffff80097bfa9f 00000000fffffffe 0000000000000030 000000000000000a
[  867.148937] fb80: 00000000000224d6 0000000000000000 ffffff800813b204 0000007fb096c8a0
[  867.148944] [<ffffff8000ef0024>] init_oopsdemo+0x24/0x38 [oops_module]
[  867.148953] [<ffffff80080830f8>] do_one_initcall+0x78/0x194
[  867.148958] [<ffffff800818d2d0>] do_init_module+0x64/0x1c0
[  867.148962] [<ffffff800813ab5c>] load_module+0x199c/0x1ed0
[  867.148964] [<ffffff800813b2b4>] SyS_finit_module+0xb0/0xbc
[  867.148968] [<ffffff8008082f70>] el0_svc_naked+0x24/0x28
[/cc]
栈回溯信息,可以从中看出函数调用关系
[cc lang="cpp"]
[  867.148972] Code: 95ca7426 d2800000 528102e1 72a32ec1 (b9000001)
[  867.148975] ---[ end trace 1983a52768236533 ]--- Segmentation fault
[/cc]
code是错误发生时PC指向的地址处的开头20字节的代码,括号里的是出错的具体指令。

如何根据OOPS找出bug

确定出错位置在内核函数还是驱动

System.map文件记录了所有符号的运行地址,这里的符号可以理解成函数名和变量。 System.map一般在内核编译完成后,根目录下生成。

[cc lang="cpp"]
0000000000000000 A __rela_size 0000000000000000 A _kernel_flags_le_hi32 0000000000000000 A _kernel_offset_le_hi32 0000000000000000 A _kernel_size_le_hi32 000000000000000a A _kernel_flags_le_lo32 0000000000000200 A PECOFF_FILE_ALIGNMENT 0000000000080000 A _kernel_offset_le_lo32 000000000159e638 A __rela_offset 0000000001800000 A _kernel_size_le_lo32 ffffff8008080000 t _head ffffff8008080000 T _text ffffff8008080800 T __exception_text_start ffffff8008080800 T _stext ffffff8008080800 T do_undefinstr ffffff8008080a18 T do_sysinstr ffffff8008080ab4 T do_mem_abort ffffff8008080b60 T do_sp_pc_abort ffffff8008080c34 T do_debug_exceptio ............. ffffff8009879a48 b __key.30413 ffffff8009879a48 b __key.30416 ffffff8009879a48 b __key.48814 ffffff8009879a48 b __key.48818 ffffff8009879a48 b __key.48819 ffffff8009879a48 b __key.48820 ffffff8009879a48 b __key.48821 ffffff800987a000 B idmap_pg_dir ffffff800987d000 B swapper_pg_dir ffffff800987f000 B tramp_pg_dir ffffff8009880000 B _end

[/cc]

System.map中内核函数的范围是: ffffff8008080000 ~ ffffff8009880000 。而PC出错的位置是 ffffff8000ef0024 。 所以,可以判定不是内核函数出错引起的,而是某个驱动模块。

如果把oops_module.ko直接编译进ko kernel中,就是内核引起的错误了。PC出错时的地址也会刚好在System.map中。

反汇编驱动文件

 

参考指令:
arm-linux-gnueabihf-objdump -CSgd usb_test.o > my.dump,根据oops信息定位代码。

而OOPS信息也告诉我们,错误是出在了 init_oopsdemo 。

[cc lang="cpp"]

[17981.657899] PC is at init_oopsdemo+0x24/0x38 [oops_module]
[17981.658385] LR is at init_oopsdemo+0x18/0x38 [oops_module]

[/cc]
那如果OOPS没有打印出出错驱动的名字呢?
我们可以使用  cat /proc/kallsyms > kallsyms.txt 命令,在 kallsyms.txt 中找出与PC值接近的符号。 kallsyms.txt 内容如下。
[cc lang="cpp"]
ffffff8008080800 T do_undefinstr
ffffff8008080800 T _stext
ffffff8008080800 T __exception_text_start
ffffff8008080a18 T do_sysinstr
ffffff8008080ab4 T do_mem_abort
ffffff8008080b60 T do_sp_pc_abort
ffffff8008080c34 T do_debug_exception
.........
ffffff80094cfc0c T sparse_mem_map_populate
ffffff80094cfc64 T _einittext
0000000000000000 a oops_module.c        [oops_module]
ffffff8000ef0000 t $x   [oops_module]
ffffff8000ef0000 t init_oopsdemo        [oops_module]
ffffff8000ef0030 t $d   [oops_module]
ffffff8000ef0038 t $x   [oops_module]
ffffff8000ef0038 t cleanup_oopsdemo     [oops_module]
ffffff8000ef0058 t $d   [oops_module]
ffffff800bee40c8 ? __UNIQUE_ID_license2 [oops_module]
ffffff800bee40d4 ? __UNIQUE_ID_author1  [oops_module]
ffffff800bee40e3 ? __UNIQUE_ID_license0 [oops_module]
ffffff800befb368 n $d   [oops_module]
0000000000000000 a oops_module.mod.c    [oops_module]
ffffff8000ef2000 d $d   [oops_module]
ffffff800bee40f8 ? $d   [oops_module]
ffffff800bee40f8 ? __module_depends     [oops_module]
ffffff800bee4101 ? __UNIQUE_ID_vermagic0        [oops_module]
ffffff8000ef2000 d __this_module        [oops_module]
ffffff8000ef0038 t cleanup_module       [oops_module]
ffffff8000ef0000 t init_module  [oops_module]
ffffff800818d0ac u printk       [oops_module]
ffffff800808e770 u _mcount      [oops_module]
[/cc]
从上面可以看出,PC的值和 ffffff8000ef0058 很接近。所以,基本可以确定出错的模块是 oops_module 。而这个模块正是我自己写的例程。
接下来,我们就要准备反汇编 oops_module.ko 了,根据反汇编可以进一步确认出错的行数。
[cc lang="cpp"]
aarch64-linux-gnu-objdump  -D oops_module.ko  > oops_module.dis
[/cc]
oops_module.dis  内容如下
[cc lang="cpp"]
oops_module.ko:     file format elf64-littleaarch64
Disassembly of section .note.gnu.build-id:

0000000000000000 <.note.gnu.build-id>:
0:   00000004        .inst   0x00000004 ; undefined
4:   00000014        .inst   0x00000014 ; undefined
8:   00000003        .inst   0x00000003 ; undefined
c:   00554e47        .inst   0x00554e47 ; undefined
10:   70d55614        adr     x20, fffffffffffaaad3 <__UNIQUE_ID_vermagic0+0xfffffffffffaaa9a>
14:   56a7eb64        .inst   0x56a7eb64 ; undefined
18:   a66fbdf8        .inst   0xa66fbdf8 ; undefined
1c:   2b31c03f        cmn     w1, w17, sxtw
20:   bd9e1ffe        .inst   0xbd9e1ffe ; undefined

Disassembly of section .text:

0000000000000000 <init_module>:
0:   a9bf7bfd        stp     x29, x30, [sp, #-16]!
4:   910003fd        mov     x29, sp
8:   aa1e03e0        mov     x0, x30
c:   94000000        bl      0 <_mcount>
10:   58000100        ldr     x0, 30 <init_module+0x30>
14:   94000000        bl      0 <printk>
18:   d2800000        mov     x0, #0x0                        // #0
1c:   528102e1        mov     w1, #0x817                      // #2071
20:   72a32ec1        movk    w1, #0x1976, lsl #16
24:   b9000001        str     w1, [x0]
28:   a8c17bfd        ldp     x29, x30, [sp], #16
2c:   d65f03c0        ret
...

0000000000000038 <cleanup_module>:
38:   a9bf7bfd        stp     x29, x30, [sp, #-16]!
3c:   910003fd        mov     x29, sp
40:   aa1e03e0        mov     x0, x30
44:   94000000        bl      0 <_mcount>
48:   58000080        ldr     x0, 58 <cleanup_module+0x20>
4c:   94000000        bl      0 <printk>
50:   a8c17bfd        ldp     x29, x30, [sp], #16
54:   d65f03c0        ret
...

Disassembly of section .modinfo:

0000000000000000 <__UNIQUE_ID_license2>:
0:   6563696c        fnmls   z12.h, p2/m, z11.h, z3.h
4:   3d65736e        ldr     b14, [x27, #2396]
8:   004c5047        .inst   0x004c5047 ; undefined
[/cc]
根据反汇编和之前  PC is at init_oopsdemo+0x24/0x38 [oops_module] ,可以确定发生错误的是0x24的位置。
[cc lang="cpp"]
24:   b9000001        str     w1, [x0] #将w1寄存器的值,传送到地址值为x0的(存储器)内存中
[/cc]
而根据 18: d2800000 mov x0, #0x0 // #0  可以确定x0 为0。
到这里也基本可以确定,是w1的值赋值给0地址时出错了。

其他方法

gdb

[cc lang="cpp"]
oops_module aarch64-linux-gnu-gdb  -q ./oops_module.ko
Reading symbols from ./oops_module.ko...done.
(gdb) list *init_oopsdemo+0x24
0x4c is in init_oopsdemo (/home/zhongyi/code/module/oops_module/oops_module.c:10).
5       MODULE_AUTHOR("ZHONGYI");
6
7       static  int init_oopsdemo(void)
8       {
9           printk("oops module init! \n");
10          *((int*)0x00) = 0x19760817;
11          return 0;
12      }
13
14      module_init(init_oopsdemo);
(gdb)

[/cc]

addr2line

Linux下addr2line命令用于将程序指令地址转换为所对应的函数名、以及函数所在的源文件名和行号。当含有调试信息(-g)的执行程序出现crash时(core dumped),可使用addr2line命令快速定位出错的位置。
如果无法确定文件名或函数名,addr2line将在它们的位置打印两个问号;如果无法确定行号,addr2line将打印0或一个问号。
参数说明:

  • -a:在函数名、文件名和行号信息之前,以十六进制形式显示地址。
  • -b:指定目标文件的格式为bfdname。
  • -C:将低级别的符号名解码为用户级别的名字。
  • -e:指定需要转换地址的可执行文件名,默认文件是a.out。
  • -f:在显示文件名、行号信息的同时显示函数名。
  • -s:仅显示每个文件名(the base of each file name)去除目录名。
  • -i:如果需要转换的地址是一个内联函数,则还将打印返回第一个非内联函数的信息。
  • -j:读取指定section的偏移而不是绝对地址。
  • -p:使打印更加人性化:每个地址(location)的信息都打印在一行上。
  • -r:启用或禁用递归量限制。
  • --help:打印帮助信息。
  • --version:打印版本号。

[cc lang="cpp"]

oops_module aarch64-linux-gnu-addr2line -e ./oops_module.ko -p -f 0x24
init_oopsdemo at /home/zhongyi/code/module/oops_module/oops_module.c:10
➜  oops_module cat /home/zhongyi/code/module/oops_module/oops_module.c | tail -n  +5 | head -n 10
MODULE_AUTHOR("ZHONGYI");

static  int init_oopsdemo(void)
{
printk("oops module init! \n");
*((int*)0x00) = 0x19760817;
return 0;
}

module_init(init_oopsdemo);

[/cc]

decodecode

在linux内核里面有很多脚本工具,位于linux/scripts/,里面有一个decodecode工具可以用来转换机器码,decodecode脚本可以在没有源代码或符号表的情况下,将oops异常的log作为输入就可以解析出错误位置的汇编代码。

oops_log.txt 内容如下

[cc lang="cpp"]

call trace:
[  867.148911] Exception stack(0xffffffc00a4ffa70 to 0xffffffc00a4ffba0)
[  867.148913] fa60:                                   ffffff8000ef0000 0000008000000000
[  867.148916] fa80: ffffffc00a4ffc40 ffffff8000ef0024 ffffff80097c02f8 0000000000000002
[  867.148918] faa0: ffffffc00a4ffac0 000000020001b57c 0000000000000000 0000000100000000
[  867.148921] fac0: ffffffc00a4ffb60 ffffff800810d674 ffffffc00a4ffbc0 ffffff8000ef1024
[  867.148924] fae0: ffffffc0cdce10c0 ffffff80095b7860 0000000000000000 ffffff8000ef2050
[  867.148927] fb00: 0000000000000001 ffffffc0cde6e880 0000000000000000 0000000019760817
[  867.148929] fb20: 0000000000000007 0000000000000007 0000000000000001 ffffffc0f7f24b38
[  867.148932] fb40: 0000000000000022 ffffff80096280b0 ffffff8008463c3c 0000000005f5e0ff
[  867.148935] fb60: ffffff80097bfa9f 00000000fffffffe 0000000000000030 000000000000000a
[  867.148937] fb80: 00000000000224d6 0000000000000000 ffffff800813b204 0000007fb096c8a0
[  867.148944] [<ffffff8000ef0024>] init_oopsdemo+0x24/0x38 [oops_module]
[  867.148953] [<ffffff80080830f8>] do_one_initcall+0x78/0x194
[  867.148958] [<ffffff800818d2d0>] do_init_module+0x64/0x1c0
[  867.148962] [<ffffff800813ab5c>] load_module+0x199c/0x1ed0
[  867.148964] [<ffffff800813b2b4>] SyS_finit_module+0xb0/0xbc
[  867.148968] [<ffffff8008082f70>] el0_svc_naked+0x24/0x2

[/cc]

[cc lang="cpp"]

$ ARCH=arm64 CROSS_COMPILE=/home/zhongyi/code/rk3399_linux_release_v2.5.1_20210301/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- ./scripts/decodecode < /home/zhongyi/code/module/oops_module/oops_log.txt

Code: 95ca7426 d2800000 528102e1 72a32ec1 (b9000001)
All code
========
0:   95ca7426        .word   0x95ca7426
4:   d2800000        .word   0xd2800000
8:   528102e1        .word   0x528102e1
c:   72a32ec1        .word   0x72a32ec1
10:*  b9000001        .word   0xb9000001              <-- trapping instruction

Code starting with the faulting instruction
===========================================
0:   b9000001        .word   0xb9000001

[/cc]

执行脚本后,就可以得到出错的汇编代码。 trapping instruction 指出了出错的地址。根据oop_module.ko的反汇编可以知道出错的位置 24: b9000001 str w1, [x0] 。

注意:脚本认为该机器码是跟host结构相同的原生机器码,想要跨架构翻译要指定架构和交叉工具链。

faddr2line

内核开发者为了方便问题的排查,也经常需要根据内核栈,快速定位导致问题发生的代码位置。所以,Linux 内核维护了一个 faddr2line 脚本,根据 函数名+偏移量 输出源码文件名和行号。
在使用这个脚本之前,还需要注意两个前提条件:

  • 第一,带有调试信息的内核文件,一般名字为 vmlinux(注意,/boot 目录下面的 vmlinz 是压缩后的内核,不可以直接拿来使用)。
  • 第二,系统中需要安装 awk、readelf、addr2line、size、nm 等命令。对于第二个条件,这些命令都包含在 binutils 软件包中,只需要执行 apt 或者 dnf 命令安装即可。

而对第一个条件中的内核调试信息,各个主要的发行版也都提供了相应的软件仓库,你可以根据文档进行安装。比如,对于 Ubuntu 来说,你可以执行下面的命令安装调试信息:

codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/ddebs.list << EOF
deb http://ddebs.ubuntu.com/ ${codename}      main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-updates  main restricted universe multiverse
EOF
sudo apt-get install -y ubuntu-dbgsym-keyring
sudo apt-get update
sudo apt-get install -y linux-image-$(uname -r)-dbgsym

由于我们这里的oops 是发生在ko中,而不是内核。因此,使用faddr2line指定 oops_module.ko  即可。

[cc lang="cpp"]

kernel git:(firefly) ✗ scripts/faddr2line  /home/zhongyi/code/module/oops_module/oops_module.ko init_oopsdemo+0x24
init_oopsdemo+0x24/0x30:
init_oopsdemo at /home/zhongyi/code/module/oops_module/oops_module.c:18

[/cc]
如果oops发生在内核中,将oops_module.ko 换成对应的vmlinux即可。
最后,贴下oops_module.c的源代码,感兴趣的大家可以自己写一个分析下。
[cc lang="cpp"]

#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("BSD/GPL");
MODULE_AUTHOR("ZHONGYI");

static  int init_oopsdemo(void)
{
printk("oops module init! \n");
*((int*)0x00) = 0x19760817;
return 0;
}

module_init(init_oopsdemo);

static  void cleanup_oopsdemo(void)
{
printk("oops module exit! \n");
}

module_exit(cleanup_oopsdemo);
MODULE_LICENSE("GPL");

[/cc]

kworker进程 -案例[转]

原文地址:闲里偷忙的CPU - 知乎 (zhihu.com)

有一类比较特殊的CPU使用率问题,这类问题的特点是,系统平均CPU使用率很低,但是个别CPU的使用率非常高。今天借助这个真实案例,来跟大家探讨一下这类问题的解题思路。

四平八稳的kworker进程

如下图,客户提交问题的时候描述,kworker这个进程会把单个CPU几乎跑满。看到问题截图,我的第一反应是,客户是不是算错了?这台ECS实例有56个vCPU,客户是不是没有把这76%平均到每个CPU上去啊。平均一下才1.x%,这是相当可以接受啊。

事实证明,还是我太简单了。下边是客户提供的第二张图。仔细观察这张图之后,才发现第24号CPU在内核空间下CPU使用率是73.1%。这个值约等于上图中的76%。这两张图说明,客户所描述的问题,是真实存在的。

闲里偷忙

在多核环境里,我们能见到的,CPU使用率的问题,大多是每个CPU的使用率都比较高。进程调度算法的一个最主要目标,就是保证不会有有的人撑死,有的人饿死的情况发生。能影响这种“公平性”的因素有两个,一个是优先级(priority),另外一个是相关性(affinity)。优先级处理的是进程之间,哪个比较重要的问题;相关性处理的是进程需要某一个CPU专门负责的问题。

相关性会引起“闲里偷忙”这种问题是显而易见的。如果一个进程被绑定到某一个CPU,那么如果这个进程持续的做计算,势必会让这一个CPU占用率变高。当前这个问题属于这一类。至于优先级和这类问题的关联,不是那么明显。优先级在一些特殊的状况下,会制造类似的麻烦,有机会我会借助例子来分析。

工作队列

相信观察仔细的同学,会发现第一张图里,kworker进程名字后边跟了24:2这样的标识。这个和大多数其他进程是不一样的。我们先从这两个数字背后的机制,工作队列说起。

关于工作队列(work queue),这边有五个核心的概念,分别是工作(work,也就是需要做的事情,分装一个函数),工作池(work pool,工作需要一个一个处理,这是一个工作的集合),工人(worker,实现为内核进程),工人小组(worker pool,工人小团队)以及第五个概念。中介,中介是把工作队列和工人小组联系起来的纽带。工作队列这个机制,是为了保证,每一个work,从被放在工作池里,然后经过中介的手,分配给某一个工人小组的某一个工人去处理,这一切都能高效有序的进行。

对每个CPU,系统会创建两个的工作小组,普通优先级组,和高优先级组。系统会根据工作多少,动态管理每个工人小组里,工人的数量。下边是从网上拿的一张图,这张图对应一个CPU的(普通优先级在上、高优先级在下)两个工作小组。我们可以看到,每个worker被实现为一个kworker进程。而kworker后边的两个数字,大家应该可以猜到,第一个代表的是CPU的编号,第二个代表着一个工人在工人小组里的编号。当前这个问题中,kworker是第24个CPU的第2个worker。这也是为什么,在第二张图里,第24个CPU的系统使用率高的。

备注:关于工作队列,我这里其实省略了很多细节,而且work pool这个概念是不存在的,它原本是work queue,为了区分这个概念,和工作队列这个机制本身,我稍微修改了一下。

调用栈

到目前为止,我们的结论是,24号CPU的2号kworker进程在持续的使用CPU资源。那为什么这个进程会持续使用CPU资源呢?两种典型情况:一是有一个工作本身定义有问题,怎么做也做不完。二是有很多工作源源不断的交给这个工人。要知道是哪种情况,第一件可以做的事,是看进程(线程)的调用栈。

这是一张在客户系统里的截图,我连续查看stack文件内容,发现可以看到的调用栈,都是最终到worker_thread就结束了。这显然是不够的。因为worker_thread是属于framework的一部分,framework相当于电路,要知道家里为什么电费高,一般情况下只看电路是没用的,还是要看挂载电路上的电器是什么。

ftrace

除了stack文件,下一个可以使用的神器是ftrace。ftrace不是一个程序,虽然它的名字和ltrace,和strace像是同类,但其实ftrace完全另外一回事。简单点说,ftrace是一种内核追踪的机制,这种机制集成在内核里,它会根据用户的设置,提供给用户某一方面的日志供调试所用。当前这个问题与工作队列有关,下图是ftrace实现的与工作队列相关的几个事件追踪开关。

其中workqueue_queue_work,显然可以追踪把工作添加到工作队列的事件。开启这个事件追踪,在客户系统里,我拿到下边的日志。

这个日志,能说明三个问题:第一,高CPU使用率并不是某一个有问题的工作导致的,而是很多工作被不断地添加到工作队列里,并分派到24号CPU上导致的;第二,这些工作对应一个函数,就是nf_conntrack这个模块的gc_worker函数;第三,work struct指针从头到尾都没有变化,说明同样一个work被重复添加。

备注:关于ftrace的更多细节,这里不再详述,如果感兴趣,或者用到的时候,请自行Google。

如何打开tracing?

perf

问题进展到这一步,我还是想搞清楚使用CPU资源高的调用栈是什么样子,因为这才是真正的实锤。其间我想到向sysrq-trigger文件写入l字符来产生所有CPU上运行的call stack,但是最终还是怕出事没有做。sysrq确实是一个看起来比较吓人的机制。

下一个可用的工具是perf,很巧的是,我发现客户系统安装了这个工具。而比这更巧的事情是,我发现客户在root目录下,居然有一份收集好的perf日志。顺手用perf report分析这份日志,得到下边输出。很显然这里有我想要的调用栈。而这个调用栈完全匹配之前用其他工具得到的结果。

源码分析&建议

知道导致问题的调用栈,下边能做的,只有代码分析。

gc_worker是nf_conntrack模块里定义的,用来执行conntrack表项超时回收任务的一个函数,而这个函数会在自己的结尾处,以一定的延迟策略,重新把自己queue到工作队列中去。这也是为什么我们在ftrace日志里看到所有的work struct指针都不变的原因。

确定了问题是由大量gc_worker工作导致的,那么,从逻辑上来讲,有三个方向可以去调优这个问题。第一个是,让gc_worker的工作分摊到所有的CPU上去。但这个方案必须有内核相关配置项支持。可惜的是,工作队列的代码逻辑为了保证效率,采取了就近原则。就是说,一个工作,运行在一个CPU上,去queue另外一个工作,那么被queue的工作也会被放在同样的CPU上执行。第二个是,根据网络环境,优化gc_worker的相关参数。第三个是,把所有业务进程提升到实时优先级,这样,当业务进程被分派到kworker使用的这个CPU的时候,会抢占kworker,从而保证业务不受影响。

在不能修改内核代码的情况下,我强烈建议客户用第三个方案。

客户的选择

客户最终选择了第二个方案,而且做的比我预想的要彻底,他们直接修改了nf_conntrack这个模块。通过修改影响gc_worker延迟策略相关的参数,保证gc_worker以比较低的频率被执行,从而解决了这个问题。