[20261004]bpftrace查看oracle函数调用堆栈问题.txt
[20261004]bpftrace查看oracle函数调用堆栈问题.txt
--//使用bpftrace建立脚本查看oracle sskgphpjw调用堆栈的问题,做一个记录:
--//前面的分析已经确定sskgphpjw函数用来计算Semaphore Arrays Key,bpftrace脚本跟踪sskgphpjw函数,无意间发现参与字符串运算
--//存在某个规律,很明显每次运算的ascii码在原来的基础上+1.
# bpftrace sskgphpjw.bt 0
Attached 2 probes
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=book/u01/app/oracle/product/21.0.0/dbhome_1
[16:22:49] sskgphpjw pid=5033 return hash_value=0x5507207c 1426530428
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2
[16:22:49] sskgphpjw pid=5033 return hash_value=0x7e0edb60 2114902880
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3
[16:22:49] sskgphpjw pid=5033 return hash_value=0x99eaaedc 2582294236
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=errn2x342dss2rudfoh2surgxfw25413132gekrphb4
[16:22:49] sskgphpjw pid=5033 return hash_value=0x32fcf5bc 855438780
--//想了解oracle的代码如何实现,结果提交了几个函数的汇编代码给deepseek分析,发现都不是,后面找到一个sskgpbitspersem,结
--//果分析还是不对,最终确定在sskgpwidtokeys函数里面。
--//问题主要原因基本都是认真定位,看调用sskgphpjw的执行堆栈时,使用bpftrace的print(ustack)功能有点小瑕疵,通过例子说明问
--//题。
$ cat sskgphpjw1.bt
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
$len = * (uint64 *)(arg0 + 0x100);
printf("[%s] %s pid=%d ptr=0x%016lx len=%lu str=%s\n", strftime("%H:%M:%S", nsecs), func, pid, arg0, $len,buf(arg0,$len));
print(ustack);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d return hash_value=0x%08lx %lu\n", strftime("%H:%M:%S", nsecs), func, pid, retval, retval);
}
--//跟踪结果如下:
# bpftrace sskgphpjw1.bt 0
Attached 2 probes
[15:04:40] sskgphpjw pid=3008 ptr=0x00007fff1ed25860 len=43 str=book/u01/app/oracle/product/21.0.0/dbhome_1
sskgphpjw+0
sskgpwcr+303
skgpwinit+838
ksunfy+2957
kscnfy+1212
ksmcsg+2174
opistr_real+774
opistr+341
opiodr+1256
ttcpip+1257
opitsk+1906
opiino+1008
opiodr+1256
opidrv+1067
sou2o+165
opimai_real+400
ssthrdmain+412
main+292
__libc_start_call_main+128
[15:04:40] sskgphpjw pid=3008 return hash_value=0x5507207c 1426530428
....
--//从调用堆栈可以发现前2个是sskgphpjw+0,sskgpwcr+303.
--//303 = 0x12f
$ objdump --prefix-addresses -d --disassemble=sskgpwcr /u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle | grep callq
00000000057b526d <sskgpwcr+0x7d> callq *%rax
00000000057b52a2 <sskgpwcr+0xb2> callq *0x18(%rax)
00000000057b531a <sskgpwcr+0x12a> callq 00000000057b58c0 <sskgpwidtokeys>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00000000057b532e <sskgpwcr+0x13e> callq 0000000000e8cfa0 <uname@plt>
00000000057b5357 <sskgpwcr+0x167> callq 0000000014faa910 <sscanf>
00000000057b53e5 <sskgpwcr+0x1f5> callq *%r10
00000000057b5405 <sskgpwcr+0x215> callq 00000000057b5df0 <sskgpsemspersemid>
00000000057b545b <sskgpwcr+0x26b> callq *%r10
00000000057b5483 <sskgpwcr+0x293> callq 00000000057b6100 <sskgpwfindops>
00000000057b54d8 <sskgpwcr+0x2e8> callq *-0x78(%rbp)
00000000057b5502 <sskgpwcr+0x312> callq 00000000057b6490 <sskgpremovesem>
00000000057b5534 <sskgpwcr+0x344> callq 00000000057b65d0 <sskgpcreatesem>
00000000057b55b7 <sskgpwcr+0x3c7> callq 0000000004f9bb30 <slosFillErr>
00000000057b55ec <sskgpwcr+0x3fc> callq 0000000004f9bb30 <slosFillErr>
00000000057b5625 <sskgpwcr+0x435> callq 0000000015336780 <skgoprint>
00000000057b5674 <sskgpwcr+0x484> callq 0000000004f9bb30 <slosFillErr>
00000000057b56ab <sskgpwcr+0x4bb> callq 0000000015336780 <skgoprint>
00000000057b56e4 <sskgpwcr+0x4f4> callq 0000000004f9bb30 <slosFillErr>
00000000057b571a <sskgpwcr+0x52a> callq 0000000015336780 <skgoprint>
00000000057b5745 <sskgpwcr+0x555> callq 00000000057b6100 <sskgpwfindops>
00000000057b5756 <sskgpwcr+0x566> callq 00000000057b5df0 <sskgpsemspersemid>
00000000057b57c1 <sskgpwcr+0x5d1> callq *%rcx
00000000057b57f1 <sskgpwcr+0x601> callq *%rdx
00000000057b57fb <sskgpwcr+0x60b> callq 00000000057b6da0 <sskgpfthrinit>
00000000057b580f <sskgpwcr+0x61f> callq 00000000057b5a30 <sskgphpjw>
00000000057b5820 <sskgpwcr+0x630> callq *0x14ad41da(%rip) # 000000001a289a00 <sskgp_fthread_ipc_instance_create_fp>
00000000057b5849 <sskgpwcr+0x659> callq 0000000004f9bb30 <slosFillErr>
--//偏移0x12f之前的调用是sskgpwidtokeys,而前面bpftrace的print(ustack);并没有显示出来.
$ objdump --prefix-addresses -d --start-address=0x00000000057b531a --stop-address=0x00000000057b5357 /u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle
/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle: file format elf64-x86-64
Disassembly of section .text:
00000000057b531a <sskgpwcr+0x12a> callq 00000000057b58c0 <sskgpwidtokeys>
00000000057b531f <sskgpwcr+0x12f> test %eax,%eax
00000000057b5321 <sskgpwcr+0x131> je 00000000057b55bc <sskgpwcr+0x3cc>
00000000057b5327 <sskgpwcr+0x137> lea -0x210(%rbp),%rdi
00000000057b532e <sskgpwcr+0x13e> callq 0000000000e8cfa0 <uname@plt>
00000000057b5333 <sskgpwcr+0x143> test %eax,%eax
00000000057b5335 <sskgpwcr+0x145> jne 00000000057b57c8 <sskgpwcr+0x5d8>
00000000057b533b <sskgpwcr+0x14b> lea 0x105a060e(%rip),%rsi # 0000000015d55950 <kwqsupqcov+0x470>
00000000057b5342 <sskgpwcr+0x152> lea -0x18e(%rbp),%rdi
00000000057b5349 <sskgpwcr+0x159> xor %eax,%eax
00000000057b534b <sskgpwcr+0x15b> lea -0x40(%rbp),%rdx
00000000057b534f <sskgpwcr+0x15f> lea -0x3c(%rbp),%rcx
00000000057b5353 <sskgpwcr+0x163> lea -0x38(%rbp),%r8
$ objdump --prefix-addresses -d --disassemble=sskgpwidtokeys /u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle | grep callq
00000000057b5930 <sskgpwidtokeys+0x70> callq 00000000057b5be0 <sskgpbitspersem>
00000000057b5968 <sskgpwidtokeys+0xa8> callq 00000000057b5a30 <sskgphpjw>
00000000057b59e0 <sskgpwidtokeys+0x120> callq 00000000057b5d00 <sskgph2>
--//调用sskgpwidtokeys,最多涉及三个函数<sskgpbitspersem>,<sskgphpjw>, <sskgph2>。
--//建立脚本sskgphpjw.bt,看看调用sskgpwidtokeys里面的执行关系。
$ cat sskgphpjw.bt
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpwidtokeys
/ $1 == 0 || pid == $1 /
{
printf("\n%s Begin\n",func);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpwidtokeys
/ $1 == 0 || pid == $1 /
{
printf("%s End\n",func);
}
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpbitspersem,
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgph2
/ $1 == 0 || pid == $1 /
{
printf("%s Begin\n",func);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpbitspersem,
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgph2
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d return hash_value=0x%08lx %lu\n", strftime("%H:%M:%S", nsecs), func, pid, retval, retval);
printf("%s End\n",func);
}
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
$len = * (uint64 *)(arg0 + 0x100);
printf("[%s] %s pid=%d ptr=0x%016lx len=%lu str=%s\n", strftime("%H:%M:%S", nsecs), func, pid, arg0, $len,buf(arg0,$len));
//print(ustack);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d return hash_value=0x%08lx %lu\n", strftime("%H:%M:%S", nsecs), func, pid, retval, retval);
}
# bpftrace sskgphpjw.bt 0
Attached 8 probes
sskgpwidtokeys Begin
sskgpbitspersem Begin
[15:23:10] sskgpbitspersem pid=3468 return hash_value=0x0000000e 14
sskgpbitspersem End
[15:23:10] sskgphpjw pid=3468 ptr=0x00007ffc8cadc7e0 len=43 str=book/u01/app/oracle/product/21.0.0/dbhome_1
[15:23:10] sskgphpjw pid=3468 return hash_value=0x5507207c 1426530428
[15:23:10] sskgphpjw pid=3468 ptr=0x00007ffc8cadc7e0 len=43 str=cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2
[15:23:10] sskgphpjw pid=3468 return hash_value=0x7e0edb60 2114902880
[15:23:10] sskgphpjw pid=3468 ptr=0x00007ffc8cadc7e0 len=43 str=dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3
[15:23:10] sskgphpjw pid=3468 return hash_value=0x99eaaedc 2582294236
[15:23:10] sskgphpjw pid=3468 ptr=0x00007ffc8cadc7e0 len=43 str=errn2x342dss2rudfoh2surgxfw25413132gekrphb4
[15:23:10] sskgphpjw pid=3468 return hash_value=0x32fcf5bc 855438780
sskgph2 Begin
[15:23:10] sskgph2 pid=3468 return hash_value=0x9937c3fd 2570568701
sskgph2 End
sskgpwidtokeys End
--//可以看出调用sskgpwidtokeys的执行顺序,先调用sskgpbitspersem,调用sskgphpjw 4次,调用sskgph2。
--//到此自己也可以大致知道,查询反汇编代码$0x4,后面跟一个跳转的地址,就知道这段代码实现asc码+1的功能。
--//总之由于使用bpftrace的print(ustack)功能有点小瑕疵,导致遗漏了分析函数sskgpwidtokeys。
--//deepseek的解析如下:
你的分析是正确的。核心结论:
1. sskgpwidtokeys 确实是 sskgphpjw 的直接调用者,调用点在 sskgpwidtokeys+0xa8。
2. bpftrace 的 ustack 跳过了 sskgpwidtokeys 这一帧,所以之前没看到它。
3. 你看到的 sskgpwcr+303(即 +0x12f)其实是 sskgpwidtokeys 的返回地址,不是 sskgphpjw 的返回地址。
## 为什么 ustack 会跳过一帧
bpftrace 的 ustack 通过读取栈上的返回地址来展开调用栈。正常情况下,sskgphpjw 被调用时,栈上的返回地址应该是:
text
sskgpwidtokeys+0xa8 的下一条指令 = sskgpwidtokeys+0xad
但你看到的却是:
text
sskgpwcr+0x12f
这正是 sskgpwidtokeys 的返回地址(callq sskgpwidtokeys 的下一条指令)。也就是说,ustack 直接跳过了 sskgpwidtokeys 的栈帧,
把它的返回地址当成了 sskgphpjw 的返回地址。
常见原因:
- 编译时省略了帧指针(-fomit-frame-pointer)。Oracle 的二进制很可能不带帧指针,bpftrace 只能用启发式方法猜栈帧,容易漏掉一层。
- sskgpwidtokeys 的栈帧布局特殊,比如它用了 sub $0x118,%rsp 分配大块局部空间,bpftrace 的展开逻辑没能正确识别。
- bpftrace 的 ustack 本身有深度或启发式限制,在复杂二进制上会漏帧。
所以不是你的分析错,是工具在这种场景下不够可靠。
## 你的验证方法是对的
你用两个手段交叉验证:
1. objdump 看调用点:sskgpwcr+0x12a 调 sskgpwidtokeys,sskgpwidtokeys+0xa8 调 sskgphpjw。
2. bpftrace 看执行顺序:sskgpwidtokeys Begin → sskgpbitspersem → sskgphpjw ×4 → sskgph2 → sskgpwidtokeys End。
两者结合,就能确定 sskgphpjw 是在 sskgpwidtokeys 内部被调用的,而不是直接从 sskgpwcr 调的。
小结
- 你的分析完全正确。
- ustack 漏掉 sskgpwidtokeys 是 bpftrace 在无帧指针二进制上的常见问题。
- 以后遇到类似情况,可以用 objdump 找调用点 + bpftrace 看函数进出顺序 来交叉验证,不依赖 ustack 的完整性。
- 这样你已经完整还原了 sskgpwidtokeys 的执行流程:
text
sskgpwidtokeys
-> sskgpbitspersem
-> sskgphpjw ×4 (base, base+1, base+2, base+3)
-> sskgph2
--//最后贴出字符串asc码+1的核心算法:
$ objdump --prefix-addresses -d --start-address=0x00000000057b5961 --stop-address=0x00000000057b59d6 /u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle
/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle: file format elf64-x86-64
Disassembly of section .text:
00000000057b5961 <sskgpwidtokeys+0xa1> lea -0x130(%rbp),%rdi
00000000057b5968 <sskgpwidtokeys+0xa8> callq 00000000057b5a30 <sskgphpjw>
00000000057b596d <sskgpwidtokeys+0xad> mov %eax,0x0(%r13,%r12,4)
00000000057b5972 <sskgpwidtokeys+0xb2> test %r14,%r14
00000000057b5975 <sskgpwidtokeys+0xb5> jbe 00000000057b59cd <sskgpwidtokeys+0x10d>
00000000057b5977 <sskgpwidtokeys+0xb7> cmp $0x10,%r14
00000000057b597b <sskgpwidtokeys+0xbb> jb 00000000057b59fb <sskgpwidtokeys+0x13b>
00000000057b597d <sskgpwidtokeys+0xbd> movdqu 0x122cc33b(%rip),%xmm1 # 0000000017a81cc0 <sskgds_elf_ident+0x12f0>
00000000057b5985 <sskgpwidtokeys+0xc5> mov %rbx,%r8
00000000057b5988 <sskgpwidtokeys+0xc8> xor %esi,%esi
00000000057b598a <sskgpwidtokeys+0xca> xor %ecx,%ecx
00000000057b598c <sskgpwidtokeys+0xcc> movdqu -0x130(%rbp,%rcx,1),%xmm0
00000000057b5995 <sskgpwidtokeys+0xd5> add $0x10,%esi
00000000057b5998 <sskgpwidtokeys+0xd8> paddb %xmm1,%xmm0
00000000057b599c <sskgpwidtokeys+0xdc> movdqu %xmm0,-0x130(%rbp,%rcx,1)
00000000057b59a5 <sskgpwidtokeys+0xe5> add $0x10,%rcx
00000000057b59a9 <sskgpwidtokeys+0xe9> cmp %rbx,%rsi
00000000057b59ac <sskgpwidtokeys+0xec> jb 00000000057b598c <sskgpwidtokeys+0xcc>
00000000057b59ae <sskgpwidtokeys+0xee> movslq %r8d,%rcx
00000000057b59b1 <sskgpwidtokeys+0xf1> mov %r8d,%esi
00000000057b59b4 <sskgpwidtokeys+0xf4> mov %r8d,%r8d
00000000057b59b7 <sskgpwidtokeys+0xf7> cmp %r14,%r8
00000000057b59ba <sskgpwidtokeys+0xfa> jae 00000000057b59cd <sskgpwidtokeys+0x10d>
00000000057b59bc <sskgpwidtokeys+0xfc> inc %esi
00000000057b59be <sskgpwidtokeys+0xfe> incb -0x130(%rbp,%rcx,1)
00000000057b59c5 <sskgpwidtokeys+0x105> inc %rcx
00000000057b59c8 <sskgpwidtokeys+0x108> cmp %r14,%rsi
00000000057b59cb <sskgpwidtokeys+0x10b> jb 00000000057b59bc <sskgpwidtokeys+0xfc>
00000000057b59cd <sskgpwidtokeys+0x10d> inc %r12
00000000057b59d0 <sskgpwidtokeys+0x110> cmp $0x4,%r12
00000000057b59d4 <sskgpwidtokeys+0x114> jb 00000000057b5961 <sskgpwidtokeys+0xa1>
--//使用bpftrace建立脚本查看oracle sskgphpjw调用堆栈的问题,做一个记录:
--//前面的分析已经确定sskgphpjw函数用来计算Semaphore Arrays Key,bpftrace脚本跟踪sskgphpjw函数,无意间发现参与字符串运算
--//存在某个规律,很明显每次运算的ascii码在原来的基础上+1.
# bpftrace sskgphpjw.bt 0
Attached 2 probes
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=book/u01/app/oracle/product/21.0.0/dbhome_1
[16:22:49] sskgphpjw pid=5033 return hash_value=0x5507207c 1426530428
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2
[16:22:49] sskgphpjw pid=5033 return hash_value=0x7e0edb60 2114902880
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3
[16:22:49] sskgphpjw pid=5033 return hash_value=0x99eaaedc 2582294236
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=errn2x342dss2rudfoh2surgxfw25413132gekrphb4
[16:22:49] sskgphpjw pid=5033 return hash_value=0x32fcf5bc 855438780
--//想了解oracle的代码如何实现,结果提交了几个函数的汇编代码给deepseek分析,发现都不是,后面找到一个sskgpbitspersem,结
--//果分析还是不对,最终确定在sskgpwidtokeys函数里面。
--//问题主要原因基本都是认真定位,看调用sskgphpjw的执行堆栈时,使用bpftrace的print(ustack)功能有点小瑕疵,通过例子说明问
--//题。
$ cat sskgphpjw1.bt
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
$len = * (uint64 *)(arg0 + 0x100);
printf("[%s] %s pid=%d ptr=0x%016lx len=%lu str=%s\n", strftime("%H:%M:%S", nsecs), func, pid, arg0, $len,buf(arg0,$len));
print(ustack);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d return hash_value=0x%08lx %lu\n", strftime("%H:%M:%S", nsecs), func, pid, retval, retval);
}
--//跟踪结果如下:
# bpftrace sskgphpjw1.bt 0
Attached 2 probes
[15:04:40] sskgphpjw pid=3008 ptr=0x00007fff1ed25860 len=43 str=book/u01/app/oracle/product/21.0.0/dbhome_1
sskgphpjw+0
sskgpwcr+303
skgpwinit+838
ksunfy+2957
kscnfy+1212
ksmcsg+2174
opistr_real+774
opistr+341
opiodr+1256
ttcpip+1257
opitsk+1906
opiino+1008
opiodr+1256
opidrv+1067
sou2o+165
opimai_real+400
ssthrdmain+412
main+292
__libc_start_call_main+128
[15:04:40] sskgphpjw pid=3008 return hash_value=0x5507207c 1426530428
....
--//从调用堆栈可以发现前2个是sskgphpjw+0,sskgpwcr+303.
--//303 = 0x12f
$ objdump --prefix-addresses -d --disassemble=sskgpwcr /u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle | grep callq
00000000057b526d <sskgpwcr+0x7d> callq *%rax
00000000057b52a2 <sskgpwcr+0xb2> callq *0x18(%rax)
00000000057b531a <sskgpwcr+0x12a> callq 00000000057b58c0 <sskgpwidtokeys>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00000000057b532e <sskgpwcr+0x13e> callq 0000000000e8cfa0 <uname@plt>
00000000057b5357 <sskgpwcr+0x167> callq 0000000014faa910 <sscanf>
00000000057b53e5 <sskgpwcr+0x1f5> callq *%r10
00000000057b5405 <sskgpwcr+0x215> callq 00000000057b5df0 <sskgpsemspersemid>
00000000057b545b <sskgpwcr+0x26b> callq *%r10
00000000057b5483 <sskgpwcr+0x293> callq 00000000057b6100 <sskgpwfindops>
00000000057b54d8 <sskgpwcr+0x2e8> callq *-0x78(%rbp)
00000000057b5502 <sskgpwcr+0x312> callq 00000000057b6490 <sskgpremovesem>
00000000057b5534 <sskgpwcr+0x344> callq 00000000057b65d0 <sskgpcreatesem>
00000000057b55b7 <sskgpwcr+0x3c7> callq 0000000004f9bb30 <slosFillErr>
00000000057b55ec <sskgpwcr+0x3fc> callq 0000000004f9bb30 <slosFillErr>
00000000057b5625 <sskgpwcr+0x435> callq 0000000015336780 <skgoprint>
00000000057b5674 <sskgpwcr+0x484> callq 0000000004f9bb30 <slosFillErr>
00000000057b56ab <sskgpwcr+0x4bb> callq 0000000015336780 <skgoprint>
00000000057b56e4 <sskgpwcr+0x4f4> callq 0000000004f9bb30 <slosFillErr>
00000000057b571a <sskgpwcr+0x52a> callq 0000000015336780 <skgoprint>
00000000057b5745 <sskgpwcr+0x555> callq 00000000057b6100 <sskgpwfindops>
00000000057b5756 <sskgpwcr+0x566> callq 00000000057b5df0 <sskgpsemspersemid>
00000000057b57c1 <sskgpwcr+0x5d1> callq *%rcx
00000000057b57f1 <sskgpwcr+0x601> callq *%rdx
00000000057b57fb <sskgpwcr+0x60b> callq 00000000057b6da0 <sskgpfthrinit>
00000000057b580f <sskgpwcr+0x61f> callq 00000000057b5a30 <sskgphpjw>
00000000057b5820 <sskgpwcr+0x630> callq *0x14ad41da(%rip) # 000000001a289a00 <sskgp_fthread_ipc_instance_create_fp>
00000000057b5849 <sskgpwcr+0x659> callq 0000000004f9bb30 <slosFillErr>
--//偏移0x12f之前的调用是sskgpwidtokeys,而前面bpftrace的print(ustack);并没有显示出来.
$ objdump --prefix-addresses -d --start-address=0x00000000057b531a --stop-address=0x00000000057b5357 /u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle
/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle: file format elf64-x86-64
Disassembly of section .text:
00000000057b531a <sskgpwcr+0x12a> callq 00000000057b58c0 <sskgpwidtokeys>
00000000057b531f <sskgpwcr+0x12f> test %eax,%eax
00000000057b5321 <sskgpwcr+0x131> je 00000000057b55bc <sskgpwcr+0x3cc>
00000000057b5327 <sskgpwcr+0x137> lea -0x210(%rbp),%rdi
00000000057b532e <sskgpwcr+0x13e> callq 0000000000e8cfa0 <uname@plt>
00000000057b5333 <sskgpwcr+0x143> test %eax,%eax
00000000057b5335 <sskgpwcr+0x145> jne 00000000057b57c8 <sskgpwcr+0x5d8>
00000000057b533b <sskgpwcr+0x14b> lea 0x105a060e(%rip),%rsi # 0000000015d55950 <kwqsupqcov+0x470>
00000000057b5342 <sskgpwcr+0x152> lea -0x18e(%rbp),%rdi
00000000057b5349 <sskgpwcr+0x159> xor %eax,%eax
00000000057b534b <sskgpwcr+0x15b> lea -0x40(%rbp),%rdx
00000000057b534f <sskgpwcr+0x15f> lea -0x3c(%rbp),%rcx
00000000057b5353 <sskgpwcr+0x163> lea -0x38(%rbp),%r8
$ objdump --prefix-addresses -d --disassemble=sskgpwidtokeys /u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle | grep callq
00000000057b5930 <sskgpwidtokeys+0x70> callq 00000000057b5be0 <sskgpbitspersem>
00000000057b5968 <sskgpwidtokeys+0xa8> callq 00000000057b5a30 <sskgphpjw>
00000000057b59e0 <sskgpwidtokeys+0x120> callq 00000000057b5d00 <sskgph2>
--//调用sskgpwidtokeys,最多涉及三个函数<sskgpbitspersem>,<sskgphpjw>, <sskgph2>。
--//建立脚本sskgphpjw.bt,看看调用sskgpwidtokeys里面的执行关系。
$ cat sskgphpjw.bt
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpwidtokeys
/ $1 == 0 || pid == $1 /
{
printf("\n%s Begin\n",func);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpwidtokeys
/ $1 == 0 || pid == $1 /
{
printf("%s End\n",func);
}
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpbitspersem,
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgph2
/ $1 == 0 || pid == $1 /
{
printf("%s Begin\n",func);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpbitspersem,
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgph2
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d return hash_value=0x%08lx %lu\n", strftime("%H:%M:%S", nsecs), func, pid, retval, retval);
printf("%s End\n",func);
}
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
$len = * (uint64 *)(arg0 + 0x100);
printf("[%s] %s pid=%d ptr=0x%016lx len=%lu str=%s\n", strftime("%H:%M:%S", nsecs), func, pid, arg0, $len,buf(arg0,$len));
//print(ustack);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d return hash_value=0x%08lx %lu\n", strftime("%H:%M:%S", nsecs), func, pid, retval, retval);
}
# bpftrace sskgphpjw.bt 0
Attached 8 probes
sskgpwidtokeys Begin
sskgpbitspersem Begin
[15:23:10] sskgpbitspersem pid=3468 return hash_value=0x0000000e 14
sskgpbitspersem End
[15:23:10] sskgphpjw pid=3468 ptr=0x00007ffc8cadc7e0 len=43 str=book/u01/app/oracle/product/21.0.0/dbhome_1
[15:23:10] sskgphpjw pid=3468 return hash_value=0x5507207c 1426530428
[15:23:10] sskgphpjw pid=3468 ptr=0x00007ffc8cadc7e0 len=43 str=cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2
[15:23:10] sskgphpjw pid=3468 return hash_value=0x7e0edb60 2114902880
[15:23:10] sskgphpjw pid=3468 ptr=0x00007ffc8cadc7e0 len=43 str=dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3
[15:23:10] sskgphpjw pid=3468 return hash_value=0x99eaaedc 2582294236
[15:23:10] sskgphpjw pid=3468 ptr=0x00007ffc8cadc7e0 len=43 str=errn2x342dss2rudfoh2surgxfw25413132gekrphb4
[15:23:10] sskgphpjw pid=3468 return hash_value=0x32fcf5bc 855438780
sskgph2 Begin
[15:23:10] sskgph2 pid=3468 return hash_value=0x9937c3fd 2570568701
sskgph2 End
sskgpwidtokeys End
--//可以看出调用sskgpwidtokeys的执行顺序,先调用sskgpbitspersem,调用sskgphpjw 4次,调用sskgph2。
--//到此自己也可以大致知道,查询反汇编代码$0x4,后面跟一个跳转的地址,就知道这段代码实现asc码+1的功能。
--//总之由于使用bpftrace的print(ustack)功能有点小瑕疵,导致遗漏了分析函数sskgpwidtokeys。
--//deepseek的解析如下:
你的分析是正确的。核心结论:
1. sskgpwidtokeys 确实是 sskgphpjw 的直接调用者,调用点在 sskgpwidtokeys+0xa8。
2. bpftrace 的 ustack 跳过了 sskgpwidtokeys 这一帧,所以之前没看到它。
3. 你看到的 sskgpwcr+303(即 +0x12f)其实是 sskgpwidtokeys 的返回地址,不是 sskgphpjw 的返回地址。
## 为什么 ustack 会跳过一帧
bpftrace 的 ustack 通过读取栈上的返回地址来展开调用栈。正常情况下,sskgphpjw 被调用时,栈上的返回地址应该是:
text
sskgpwidtokeys+0xa8 的下一条指令 = sskgpwidtokeys+0xad
但你看到的却是:
text
sskgpwcr+0x12f
这正是 sskgpwidtokeys 的返回地址(callq sskgpwidtokeys 的下一条指令)。也就是说,ustack 直接跳过了 sskgpwidtokeys 的栈帧,
把它的返回地址当成了 sskgphpjw 的返回地址。
常见原因:
- 编译时省略了帧指针(-fomit-frame-pointer)。Oracle 的二进制很可能不带帧指针,bpftrace 只能用启发式方法猜栈帧,容易漏掉一层。
- sskgpwidtokeys 的栈帧布局特殊,比如它用了 sub $0x118,%rsp 分配大块局部空间,bpftrace 的展开逻辑没能正确识别。
- bpftrace 的 ustack 本身有深度或启发式限制,在复杂二进制上会漏帧。
所以不是你的分析错,是工具在这种场景下不够可靠。
## 你的验证方法是对的
你用两个手段交叉验证:
1. objdump 看调用点:sskgpwcr+0x12a 调 sskgpwidtokeys,sskgpwidtokeys+0xa8 调 sskgphpjw。
2. bpftrace 看执行顺序:sskgpwidtokeys Begin → sskgpbitspersem → sskgphpjw ×4 → sskgph2 → sskgpwidtokeys End。
两者结合,就能确定 sskgphpjw 是在 sskgpwidtokeys 内部被调用的,而不是直接从 sskgpwcr 调的。
小结
- 你的分析完全正确。
- ustack 漏掉 sskgpwidtokeys 是 bpftrace 在无帧指针二进制上的常见问题。
- 以后遇到类似情况,可以用 objdump 找调用点 + bpftrace 看函数进出顺序 来交叉验证,不依赖 ustack 的完整性。
- 这样你已经完整还原了 sskgpwidtokeys 的执行流程:
text
sskgpwidtokeys
-> sskgpbitspersem
-> sskgphpjw ×4 (base, base+1, base+2, base+3)
-> sskgph2
--//最后贴出字符串asc码+1的核心算法:
$ objdump --prefix-addresses -d --start-address=0x00000000057b5961 --stop-address=0x00000000057b59d6 /u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle
/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle: file format elf64-x86-64
Disassembly of section .text:
00000000057b5961 <sskgpwidtokeys+0xa1> lea -0x130(%rbp),%rdi
00000000057b5968 <sskgpwidtokeys+0xa8> callq 00000000057b5a30 <sskgphpjw>
00000000057b596d <sskgpwidtokeys+0xad> mov %eax,0x0(%r13,%r12,4)
00000000057b5972 <sskgpwidtokeys+0xb2> test %r14,%r14
00000000057b5975 <sskgpwidtokeys+0xb5> jbe 00000000057b59cd <sskgpwidtokeys+0x10d>
00000000057b5977 <sskgpwidtokeys+0xb7> cmp $0x10,%r14
00000000057b597b <sskgpwidtokeys+0xbb> jb 00000000057b59fb <sskgpwidtokeys+0x13b>
00000000057b597d <sskgpwidtokeys+0xbd> movdqu 0x122cc33b(%rip),%xmm1 # 0000000017a81cc0 <sskgds_elf_ident+0x12f0>
00000000057b5985 <sskgpwidtokeys+0xc5> mov %rbx,%r8
00000000057b5988 <sskgpwidtokeys+0xc8> xor %esi,%esi
00000000057b598a <sskgpwidtokeys+0xca> xor %ecx,%ecx
00000000057b598c <sskgpwidtokeys+0xcc> movdqu -0x130(%rbp,%rcx,1),%xmm0
00000000057b5995 <sskgpwidtokeys+0xd5> add $0x10,%esi
00000000057b5998 <sskgpwidtokeys+0xd8> paddb %xmm1,%xmm0
00000000057b599c <sskgpwidtokeys+0xdc> movdqu %xmm0,-0x130(%rbp,%rcx,1)
00000000057b59a5 <sskgpwidtokeys+0xe5> add $0x10,%rcx
00000000057b59a9 <sskgpwidtokeys+0xe9> cmp %rbx,%rsi
00000000057b59ac <sskgpwidtokeys+0xec> jb 00000000057b598c <sskgpwidtokeys+0xcc>
00000000057b59ae <sskgpwidtokeys+0xee> movslq %r8d,%rcx
00000000057b59b1 <sskgpwidtokeys+0xf1> mov %r8d,%esi
00000000057b59b4 <sskgpwidtokeys+0xf4> mov %r8d,%r8d
00000000057b59b7 <sskgpwidtokeys+0xf7> cmp %r14,%r8
00000000057b59ba <sskgpwidtokeys+0xfa> jae 00000000057b59cd <sskgpwidtokeys+0x10d>
00000000057b59bc <sskgpwidtokeys+0xfc> inc %esi
00000000057b59be <sskgpwidtokeys+0xfe> incb -0x130(%rbp,%rcx,1)
00000000057b59c5 <sskgpwidtokeys+0x105> inc %rcx
00000000057b59c8 <sskgpwidtokeys+0x108> cmp %r14,%rsi
00000000057b59cb <sskgpwidtokeys+0x10b> jb 00000000057b59bc <sskgpwidtokeys+0xfc>
00000000057b59cd <sskgpwidtokeys+0x10d> inc %r12
00000000057b59d0 <sskgpwidtokeys+0x110> cmp $0x4,%r12
00000000057b59d4 <sskgpwidtokeys+0x114> jb 00000000057b5961 <sskgpwidtokeys+0xa1>
浙公网安备 33010602011771号