title: 驱动调试(四)oops确定调用树

date: 2019/1/14 19:30:32

toc: true

驱动调试(四)oops确定调用树

内核开启调用树

如果内核开启调用信息的打印

# 这个需要配置内核
#│ Symbol: FRAME_POINTER [=y] │
#│ Prompt: Compile the kernel with frame pointers │
#│ Defined at lib/Kconfig.debug:357 │
#│ Depends on: DEBUG_KERNEL && ............... │
#│ Location: │
#│ -> Kernel hacking │
#│ -> Kernel debugging (DEBUG_KERNEL [=y])

为什么这个选项叫做FRAME_POINTER,因为实际上使用了ARM中的fp寄存器,在A函数调用B函数时,B在开头保存了fb,ip,lr,pc等到栈中,一般情况下就是倒数第4个是fp,这个栈里面的fp也就是父函数的栈底

所以,在栈里面通过寻找fp,倒数第二个就能依次找到LR,依次找到调用树了

能显示出调用关系在oops中

Backtrace:
[<bf000000>] (first_drv_open+0x0/0x3c [first_drv]) from [<c008d888>] (chrdev_open+0x14c/0x164)
[<c008d73c>] (chrdev_open+0x0/0x164) from [<c0089e48>] (__dentry_open+0x100/0x1e8)
r8:c2ca741c r7:c0474d20 r6:c008d73c r5:c04b2e5c r4:c3e9b700
[<c0089d48>] (__dentry_open+0x0/0x1e8) from [<c0089f64>] (nameidata_to_filp+0x34/0x48)
[<c0089f30>] (nameidata_to_filp+0x0/0x48) from [<c0089fb8>] (do_filp_open+0x40/0x48)
r4:00000002
[<c0089f78>] (do_filp_open+0x0/0x48) from [<c008a2f4>] (do_sys_open+0x54/0xe4)
r5:be848ee0 r4:00000002
[<c008a2a0>] (do_sys_open+0x0/0xe4) from [<c008a3a8>] (sys_open+0x24/0x28)
[<c008a384>] (sys_open+0x0/0x28) from [<c002bea0>] (ret_fast_syscall+0x0/0x2c)
Code: e24cb004 e59f1024 e3a00000 e5912000 (e5923000)
Segmentation fault 调用关系如下
ret_fast_syscall
sys_open
do_filp_open
nameidata_to_filp
__dentry_open
chrdev_open
first_drv_open

栈指针分析

原理

在C函数的调用中,会先保存返回地址(LR)到栈中,也就是说LR的值是调用者的PC值.我们依次找到栈底,找到lr即可.

A()
B()
C()
{
//B的LR存到C分配的栈中
}

寄存器别名

  • r15 PC The Program Counter.
  • r14 LR The Link Register.
  • r12 IP The Intra-Procedure-call scratch register. (可简单的认为暂存SP)
  • r11 frame pointer

基础解释

  • 栈底指的是堆栈指针sp所指的起始位置

  • STMDB 先存储,后做减法,也就是sp指向的位置是栈有效的数据,寄存器高地址存高字节

    !:表示最后的地址写回到Rn中
    stmdb sp!, {fp, ip, lr, pc}

例子分析

找到PC地址的位置

可以看下上一个章节,这里使用模块装载的例子

pc : [<bf000018>]

栈分析

可以看出来栈中的fp指向了父函数的栈底,最后一个函数的fb为0,也就是一个中断函数了图片这里可能看不清,左键拖动可以查看原图(高清)

这里有具体的txt分析,还是excel的图片好看,拖动放大

r15 PC The Program Counter.
r14 LR The Link Register.
r13 SP The Stack Pointer.
r12 IP The Intra-Procedure-call scratch register. (可简单的认为暂存SP)
r11 frame pointer。 栈底指的是堆栈指针sp所指的起始位置 stmdb sp!, {fp, ip, lr, pc}
# 高地址存高字节
也就是存储如下
-------------------------------------------------------------------------------
r15 PC The Program Counter.
r14 LR The Link Register.
r12 IP The Intra-Procedure-call scratch register. (可简单的认为暂存SP)
r11 frame pointer。
-------------------------------------------------------------------------------
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00000000 <first_drv_open>:
0: e1a0c00d mov ip, sp
4: e92dd800 stmdb sp!, {fp, ip, lr, pc}
8: e24cb004 sub fp, ip, #4 ; 0x4 #这里是fp运算后是 c2c81e94
c: e59f1024 ldr r1, [pc, #36] ; 38 <__mod_vermagic5>
10: e3a00000 mov r0, #0 ; 0x0
14: e5912000 ldr r2, [r1]
18: e5923000 ldr r3, [r2] // 在这里出错 r2=56000050 #****************************************************************************
sp : c2c81e88 ip : c2c81e98 fp : c2c81e94
Stack: (0xc2c81e88 to 0xc2c82000)
1e80: xxxxxxxx xxxxxxxx c2c81ebc c2c81e98 c008d888 bf000010 00000000 c3e38be0
fp(now) ↑--fp(old) ip LR PC ---↑ 1ea0: c2c3b100 c008d73c c0474e20 c2c8e3c0 c2c81ee4 c2c81ec0 c0089e48 c008d74c
1ec0: c3e38be0 c2c81f04 00000003 ffffff9c c002c044 c070b000 c2c81efc c2c81ee8
#**************************************************************************** >>>>>>>c008d888 c008d73c <chrdev_open>:
c008d73c: e1a0c00d mov ip, sp
c008d740: e92dd9f0 stmdb sp!, {r4, r5, r6, r7, r8, fp, ip, lr, pc}
c008d744: e24cb004 sub fp, ip, #4 ; 0x4
c008d748: e24dd004 sub sp, sp, #4 ; 0x4
...
c008d888: e2507000 subs r7, r0, #0 ; 0x0 #****************************************************************************
0 4 8 C 10 14 18 1C Stack: (0xc2c81e88 to 0xc2c82000)
1e80: c2c81ebc c2c81e98 c008d888 bf000010 00000000 c3e38be0
fp(now) ↑--fp(old) ip LR PC --↑↑
1ea0: c2c3b100 c008d73c c0474e20 c2c8e3c0 c2c81ee4 c2c81ec0 c0089e48 c008d74c
fp(old) IP LR pc ↑--------这个位置正好是上面那个被调用函数存储在栈中的fp,也是这里的栈底(起始位置)
1ec0: c3e38be0 c2c81f04 00000003 ffffff9c c002c044 c070b000 c2c81efc c2c81ee8
1ee0: c0089f64 c0089d58 00000000 00000002 c2c81f68 c2c81f00 c0089fb8 c0089f40
1f00: c2c81f04 c2c8e3c0 c0474e20 00000000 00000000 c2cd9000 00000101 00000001
1f20: 00000000 c2c80000 c046dec8 c046dec0 ffffffe8 c070b000 c2c81f68 c2c81f48
#**************************************************************************** 这里sp存储了r4, r5, r6, r7, r8, fp, ip, lr, pc,然后再减去4,也就是存储了10个32位数据
这里我们看到
lr=c0089e48
fp(old)=c2c81ee4 上一级函数的栈底 >>>c0089e48 c0089d48 <__dentry_open>:
c0089d48: e1a0c00d mov ip, sp
c0089d4c: e92dddf0 stmdb sp!, {r4, r5, r6, r7, r8, sl, fp, ip, lr, pc}
....
c0089e38: e1a00005 mov r0, r5
c0089e3c: e1a01004 mov r1, r4
c0089e40: e1a0e00f mov lr, pc
c0089e44: e1a0f006 mov pc, r6
c0089e48: e250a000 subs sl, r0, #0 ; 0x0 #****************************************************************************
0 4 8 C 10 14 18 1C Stack: (0xc2c81e88 to 0xc2c82000)
1e80: c2c81ebc c2c81e98 c008d888 bf000010 00000000 c3e38be0
fp(now) ↑--fp(old) ip LR PC --↑↑
1ea0: c2c3b100 c008d73c c0474e20 c2c8e3c0 c2c81ee4 c2c81ec0 c0089e48 c008d74c
fp(old) IP LR pc ↑--------这个位置正好是上面那个被调用函数存储在栈中的fp,也是这里的栈底(起始位置)
1ec0: c3e38be0 c2c81f04 00000003 ffffff9c c002c044 c070b000 c2c81efc c2c81ee8
↑ fp(old) ip
1ee0: c0089f64 c0089d58 00000000 00000002 c2c81f68 c2c81f00 c0089fb8 c0089f40
lr pc ↑
这个地址是 c2c81ee4
正好是上一级的存在栈中的fp
1f00: c2c81f04 c2c8e3c0 c0474e20 00000000 00000000 c2cd9000 00000101 00000001
1f20: 00000000 c2c80000 c046dec8 c046dec0 ffffffe8 c070b000 c2c81f68 c2c81f48
#**************************************************************************** lr=c0089f64
fp(old)=c2c81efc c0089f30 <nameidata_to_filp>:
c0089f30: e1a0c00d mov ip, sp
c0089f34: e92dd810 stmdb sp!, {r4, fp, ip, lr, pc}
c0089f38: e24cb004 sub fp, ip, #4 ; 0x4
c0089f3c: e24dd004 sub sp, sp, #4 ; 0x4 ;sp=sp-4 也就是再多4个字节
...
c0089f5c: e58de000 str lr, [sp]
c0089f60: ebffff78 bl c0089d48 <__dentry_open>
c0089f64: e1a04000 mov r4, r0 #****************************************************************************
0 4 8 C 10 14 18 1C Stack: (0xc2c81e88 to 0xc2c82000)
1e80: c2c81ebc c2c81e98 c008d888 bf000010 00000000 c3e38be0
fp(now) ↑--fp(old) ip LR PC --↑↑
1ea0: c2c3b100 c008d73c c0474e20 c2c8e3c0 c2c81ee4 c2c81ec0 c0089e48 c008d74c
fp(old) IP LR pc ↑--------这个位置正好是上面那个被调用函数存储在栈中的fp,也是这里的栈底(起始位置)
1ec0: c3e38be0 c2c81f04 00000003 ffffff9c c002c044 c070b000 c2c81efc c2c81ee8
↑ fp(old) ip
1ee0: c0089f64 c0089d58 00000000 00000002 c2c81f68 c2c81f00 c0089fb8 c0089f40
lr pc ↑ fp(old) ip lr pc这个地址是被调用的存在栈中的fp
这个地址是 c2c81ee4
正好是上一级的存在栈中的fp
1f00: c2c81f04 c2c8e3c0 c0474e20 00000000 00000000 c2cd9000 00000101 00000001
1f20: 00000000 c2c80000 c046dec8 c046dec0 ffffffe8 c070b000 c2c81f68 c2c81f48 lr=c0089fb8
fp(old)=c2c81f68 c0089f78 <do_filp_open>:
c0089f78: e1a0c00d mov ip, sp
c0089f7c: e92dd830 stmdb sp!, {r4, r5, fp, ip, lr, pc} ;6个
c0089f80: e24cb004 sub fp, ip, #4 ; 0x4
c0089f84: e24dd054 sub sp, sp, #84 ; 0x54 #84/4=21个 21+6=27个
.....
c0089fb4: 0bffffdd bleq c0089f30 <nameidata_to_filp>
c0089fb8: e24bd014 sub sp, fp, #20 ; 0x14 #****************************************************************************
0 4 8 C 10 14 18 1C Stack: (0xc2c81e88 to 0xc2c82000)
1e80: c2c81ebc c2c81e98 c008d888 bf000010 00000000 c3e38be0
fp(now) ↑--fp(old) ip LR PC --↑↑
1ea0: c2c3b100 c008d73c c0474e20 c2c8e3c0 c2c81ee4 c2c81ec0 c0089e48 c008d74c
fp(old) IP LR pc ↑--------这个位置正好是上面那个被调用函数存储在栈中的fp,也是这里的栈底(起始位置)
1ec0: c3e38be0 c2c81f04 00000003 ffffff9c c002c044 c070b000 c2c81efc c2c81ee8
↑ fp(old) ip
1ee0: c0089f64 c0089d58 00000000 00000002 c2c81f68 c2c81f00 c0089fb8 c0089f40
lr pc ↑ fp(old) ip lr pc这个地址是被调用的存在栈中的fp
这个地址是 c2c81ee4
正好是上一级的存在栈中的fp
1f00: c2c81f04 c2c8e3c0 c0474e20 00000000 00000000 c2cd9000 00000101 00000001
1f20: 00000000 c2c80000 c046dec8 c046dec0 ffffffe8 c070b000 c2c81f68 c2c81f48
1f40: c008a16c c009fc70 00000003 00000000 c3e38be0 00000002 bedd1edc c2c81f94
fp(old)
1f60: c2c81f6c c008a2f4 c0089f88 00008520 bedd1ed4 0000860c 00008670 00000005
Ip LR PC↑刚好也是(fp_old)
1f80: c002c044 4013365c c2c81fa4 c2c81f98 c008a3a8 c008a2b0 00000000 c2c81fa8
1fa0: c002bea0 c008a394 bedd1ed4 0000860c 00008720 00000002 bedd1edc 00000001
1fc0: bedd1ed4 0000860c 00008670 00000001 00008520 00000000 4013365c bedd1ea8
1fe0: 00000000 bedd1e84 0000266c 400c98e0 60000010 00008720 00000000 00000000 fp(old)=c2c81f94
lr=c008a2f4 c008a2a0 <do_sys_open>:
c008a2a0: e1a0c00d mov ip, sp
c008a2a4: e92dddf0 stmdb sp!, {r4, r5, r6, r7, r8, sl, fp, ip, lr, pc}
c008a2a8: e24cb004 sub fp, ip, #4 ; 0x4
c008a2ac: e24dd004 sub sp, sp, #4 ; 0x4 ;10+1=11
.....
c008a2ec: ba00001d blt c008a368 <do_sys_open+0xc8>
c008a2f0: ebffff20 bl c0089f78 <do_filp_open>
c008a2f4: e1a08000 mov r8, r0 #****************************************************************************
0 4 8 C 10 14 18 1C Stack: (0xc2c81e88 to 0xc2c82000)
1e80: c2c81ebc c2c81e98 c008d888 bf000010 00000000 c3e38be0
fp(now) ↑--fp(old) ip LR PC --↑↑
1ea0: c2c3b100 c008d73c c0474e20 c2c8e3c0 c2c81ee4 c2c81ec0 c0089e48 c008d74c
fp(old) IP LR pc ↑--------这个位置正好是上面那个被调用函数存储在栈中的fp,也是这里的栈底(起始位置)
1ec0: c3e38be0 c2c81f04 00000003 ffffff9c c002c044 c070b000 c2c81efc c2c81ee8
↑ fp(old) ip
1ee0: c0089f64 c0089d58 00000000 00000002 c2c81f68 c2c81f00 c0089fb8 c0089f40
lr pc ↑ fp(old) ip lr pc这个地址是被调用的存在栈中的fp
这个地址是 c2c81ee4
正好是上一级的存在栈中的fp
1f00: c2c81f04 c2c8e3c0 c0474e20 00000000 00000000 c2cd9000 00000101 00000001
1f20: 00000000 c2c80000 c046dec8 c046dec0 ffffffe8 c070b000 c2c81f68 c2c81f48
1f40: c008a16c c009fc70 00000003 00000000 c3e38be0 00000002 bedd1edc c2c81f94
fp(old)
1f60: c2c81f6c c008a2f4 c0089f88 00008520 bedd1ed4 0000860c 00008670 00000005
Ip LR PC↑刚好也是(fp_old)
1f80: c002c044 4013365c c2c81fa4 c2c81f98 c008a3a8 c008a2b0 00000000 c2c81fa8
fp_old ip lr pc ↑ 1fa0: c002bea0 c008a394 bedd1ed4 0000860c 00008720 00000002 bedd1edc 00000001
1fc0: bedd1ed4 0000860c 00008670 00000001 00008520 00000000 4013365c bedd1ea8
1fe0: 00000000 bedd1e84 0000266c 400c98e0 60000010 00008720 00000000 00000000 lr=c008a3a8
fp_old=c2c81fa4 c008a384 <sys_open>:
c008a384: e1a0c00d mov ip, sp
c008a388: e92dd800 stmdb sp!, {fp, ip, lr, pc}
...
c008a3a4: ebffffbd bl c008a2a0 <do_sys_open>
c008a3a8: e89da800 ldmia sp, {fp, sp, pc} #****************************************************************************
0 4 8 C 10 14 18 1C Stack: (0xc2c81e88 to 0xc2c82000)
1e80: c2c81ebc c2c81e98 c008d888 bf000010 00000000 c3e38be0
fp(now) ↑--fp(old) ip LR PC --↑↑
1ea0: c2c3b100 c008d73c c0474e20 c2c8e3c0 c2c81ee4 c2c81ec0 c0089e48 c008d74c
fp(old) IP LR pc ↑--------这个位置正好是上面那个被调用函数存储在栈中的fp,也是这里的栈底(起始位置)
1ec0: c3e38be0 c2c81f04 00000003 ffffff9c c002c044 c070b000 c2c81efc c2c81ee8
↑ fp(old) ip
1ee0: c0089f64 c0089d58 00000000 00000002 c2c81f68 c2c81f00 c0089fb8 c0089f40
lr pc ↑ fp(old) ip lr pc这个地址是被调用的存在栈中的fp
这个地址是 c2c81ee4
正好是上一级的存在栈中的fp
1f00: c2c81f04 c2c8e3c0 c0474e20 00000000 00000000 c2cd9000 00000101 00000001
1f20: 00000000 c2c80000 c046dec8 c046dec0 ffffffe8 c070b000 c2c81f68 c2c81f48
1f40: c008a16c c009fc70 00000003 00000000 c3e38be0 00000002 bedd1edc c2c81f94
fp(old)
1f60: c2c81f6c c008a2f4 c0089f88 00008520 bedd1ed4 0000860c 00008670 00000005
Ip LR PC↑刚好也是(fp_old)
1f80: c002c044 4013365c c2c81fa4 c2c81f98 c008a3a8 c008a2b0 00000000 c2c81fa8
fp_old ip lr pc ↑ fp(old) ip 1fa0: c002bea0 c008a394 bedd1ed4 0000860c 00008720 00000002 bedd1edc 00000001
lr pc ↑
1fc0: bedd1ed4 0000860c 00008670 00000001 00008520 00000000 4013365c bedd1ea8
1fe0: 00000000 bedd1e84 0000266c 400c98e0 60000010 00008720 00000000 00000000 lr=c008a3a8
fp(old)=00000000 这里没有了,从下面来看 确实没有了,没有再操作fp了 ret_fast_syscall 软中断了 c002bea0 <ret_fast_syscall>:
c002bea0: e321f093 msr CPSR_c, #147 ; 0x93
c002bea4: e5991000 ldr r1, [r9]
c002bea8: e31100ff tst r1, #255 ; 0xff
c002beac: 1a000006 bne c002becc <fast_work_pending>
c002beb0: e59d1048 ldr r1, [sp, #72]
c002beb4: e5bde044 ldr lr, [sp, #68]!
c002beb8: e16ff001 msr SPSR_fsxc, r1
c002bebc: e95d7ffe ldmdb sp, {r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, sp, lr}^
c002bec0: e1a00000 nop (mov r0,r0)
c002bec4: e28dd00c add sp, sp, #12 ; 0xc
c002bec8: e1b0f00e movs pc, lr

附录:原文的excel

点击下载

驱动调试(四)oops确定调用树的更多相关文章

  1. 驱动调试(三)oops确定函数PC

    目录 驱动调试(三)oops确定函数PC 什么是oops 流程简述 代码仓库 模块例子分析 找到PC值 判断是否属于模块 查看符号表 找到模块 反汇编模块 内核例子分析 找到PC值 判断是否属于模块 ...

  2. 驱动调试-根据oops定位错误代码行

    1.当驱动有误时,比如,访问的内存地址是非法的,便会打印一大串的oops出来 1.1以LED驱动为例 将open()函数里的ioremap()屏蔽掉,直接使用物理地址的GPIOF,如下图所示: 1.2 ...

  3. 36.Linux驱动调试-根据oops定位错误代码行

    1.当驱动有误时,比如,访问的内存地址是非法的,便会打印一大串的oops出来 1.1以LED驱动为例 将open()函数里的ioremap()屏蔽掉,直接使用物理地址的GPIOF,如下图所示: 1.2 ...

  4. Linux驱动调试-根据oops的栈信息,确定函数调用过程

    上章链接入口: http://www.cnblogs.com/lifexy/p/8006748.html 在上章里,我们分析了oops的PC值在哪个函数出错的,那如何通过栈信息来查看出错函数的整个调用 ...

  5. 37.Linux驱动调试-根据oops的栈信息,确定函数调用过程

    上章链接入口: http://www.cnblogs.com/lifexy/p/8006748.html 在上章里,我们分析了oops的PC值在哪个函数出错的 本章便通过栈信息来分析函数调用过程 1. ...

  6. 【转】Android LCD(四):LCD驱动调试篇

    关键词:android LCD TFTSN75LVDS83B  TTL-LVDS LCD电压背光电压 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台 ...

  7. linux驱动调试--段错误之oops信息分析

    linux驱动调试--段错误之oops信息分析 http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=29401328&id= ...

  8. android 电容屏(二):驱动调试之基本概念篇

    平台信息: 内核:linux3.4.39系统:android4.4 平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新浪博 ...

  9. 【转】android 电容屏(三):驱动调试之驱动程序分析篇

    关键词:android  电容屏 tp 工作队列 中断 坐点计算  电容屏主要参数平台信息:内核:linux2.6/linux3.0系统:android/android4.0  平台:S5PV310( ...

随机推荐

  1. laravel项目使用appnode部署linux系统到阿里云服务器流程记录(待补充)

    使用 SSH 连接工具,如 PuTTY.XShell.SecureCRT 等,连接 Linux 服务器后(阿里云服务器命令行内直接输入appnode安装命令,版本:mysql选5.7.php选7.2) ...

  2. SQLServer之修改PRIMARY KEY

    使用SSMS数据库管理工具修改PRIMARY KEY 1.连接数据库,选择数据表->右键点击->选择设计(或者展开键,选择要修改的键,右键点击,选择修改,后面步骤相同). 2.选择要修改的 ...

  3. LeetCode算法题-Diameter of Binary Tree(Java实现)

    这是悦乐书的第257次更新,第270篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第124题(顺位题号是543).给定二叉树,您需要计算树的直径长度. 二叉树的直径是树中 ...

  4. Kafka设计解析(六)- Kafka高性能架构之道

    本文从宏观架构层面和微观实现层面分析了Kafka如何实现高性能.包含Kafka如何利用Partition实现并行处理和提供水平扩展能力,如何通过ISR实现可用性和数据一致性的动态平衡,如何使用NIO和 ...

  5. final等关键字和代码块

    一.final关键字 其作用 1.final除构造方法外均可修饰 2.修饰类:被final修饰的类是无法被继承的. 3.修饰方法,可被继承,但是无法被重写 4.修饰变量使其为常量 5.修饰引用型变量, ...

  6. PuTTY 串口调试,为普通用户增加访问串口设备权限

    一般情况下,只有 root 用户可以使用 PuTTY 访问串口设备,如果要为普通用户增加访问串口设备的权限,可按如下步骤进行: (以 Ubuntu 14.04.3 系统为例,第一个串口设备,会被识别为 ...

  7. Spring Security(三十五):Part III. Testing

    This section describes the testing support provided by Spring Security. 本节介绍Spring Security提供的测试支持. ...

  8. 理论篇-Java中一些零碎的知识点

    1. Java中length,length方法,size方法区别 length属性:用于获取数组长度. length方法:用于获取字符串长度. size方法:用于获取泛型集合有多少个元素. 2. is ...

  9. iOS开发基础-九宫格坐标(6)

    继续对iOS开发基础-九宫格坐标(5)中的代码进行优化. 优化思路:把字典转模型部分的数据处理操作也拿到模型类中去实现,即将 ViewController 类实现中 apps 方法搬到 WJQAppI ...

  10. 错误:set Assigning an instance of 'esri.***' which is not a subclass of 'esri.***‘

    1.    出现 set Assigning an instance of 'esri.***' which is not a subclass of 'esri.***‘的错误原因 是 因为没有找见 ...