jni 函数调用一些 gdb 不知道的 libc 函数
jni function calls some libc function which gdb does not know about
我有一个简单的 JNI 函数,我用它从 C 代码 UnixUtil.unsafeReadToByteArray
中将数据从文件读入 byte[]
,实现为:
JNIEXPORT jlong JNICALL Java_net_xxxxxxx_UnixUtil_unsafeReadToByteArray
(JNIEnv *e, jclass jc, jint fd, jbyteArray array, jlong offset, jlong count){
signed char *array_native_ptr = (*e) -> GetByteArrayElements(e, array, NULL);
ssize_t bytes_read = read(fd, array_native_ptr + offset, (size_t) count);
(*e) -> ReleaseByteArrayElements(e, array, array_native_ptr, 0);
return bytes_read;
}
分析 java 应用程序 运行 该函数显示了一些不明确的结果。这是顶部:
最热门的事情之一原来是来自 libc-2.27.so
地址 0x18eb1f
的一些指令。我想了解它是什么,但 gdb 不知道它
(gdb) disas 0x18eb1f
No function contains specified address
Objdump'ing libc grep 我发现的地址
18eb0b: 72 0f jb 18eb1c <__nss_group_lookup@GLIBC_2.2.5+0x24ddc>
[...]
18eb1c: 48 89 d1 mov %rdx,%rcx
18eb1f: f3 a4 rep movsb %ds:(%rsi),%es:(%rdi)
它看起来像是 __nss_group_lookup
的一部分,而 __nss_group_lookup
似乎不包含地址:
(gdb) disas __nss_group_lookup
Dump of assembler code for function __nss_passwd_lookup:
0x0000000000169d40 <+0>: mov rax,QWORD PTR [rip+0x281121] # 0x3eae68
0x0000000000169d47 <+7>: mov DWORD PTR fs:[rax],0x26
0x0000000000169d4e <+14>: mov eax,0xffffffff
0x0000000000169d53 <+19>: ret
End of assembler dump. making the things more unclear then it was before.
让事情变得比以前更不清楚了。
问题: 你能给出任何提示去哪里看以理解为什么属于 __nss_group_lookup
的指令是调用 jni_GetByteArrayElements
/jni_ReleaseByteArrayElements
时最热,实际上是什么。
我的预期是因为 jni_GetByteArrayElements
/jni_ReleaseByteArrayElements
通过 memcpy
将 byte[]
从 Java 堆复制到 C 堆,这将是最热的。
显然您系统上的 libc 不包含调试符号(共享库中没有 .symtab
部分)。因此 gdb 显示距离 .dynsym
最近的导出符号,这与实际最热门的函数无关。
rep movsb
指令表明此片段是 memcpy
实现的一部分。
安装 libc-dbg
包(或者它在您的 Linux 发行版中的称呼)。
例如在我的 Ubuntu 18.04 上,地址 __nss_group_lookup+0x24ddc
确实指向 memcpy
内部:
(gdb) disas __nss_group_lookup+0x24ddc
Dump of assembler code for function __memmove_avx_unaligned_erms:
0x00007ffffef7ead0 <+0>: mov %rdi,%rax
...
0x00007ffffef7eb1c <+76>: mov %rdx,%rcx
0x00007ffffef7eb1f <+79>: rep movsb %ds:(%rsi),%es:(%rdi)
0x00007ffffef7eb21 <+81>: retq
我有一个简单的 JNI 函数,我用它从 C 代码 UnixUtil.unsafeReadToByteArray
中将数据从文件读入 byte[]
,实现为:
JNIEXPORT jlong JNICALL Java_net_xxxxxxx_UnixUtil_unsafeReadToByteArray
(JNIEnv *e, jclass jc, jint fd, jbyteArray array, jlong offset, jlong count){
signed char *array_native_ptr = (*e) -> GetByteArrayElements(e, array, NULL);
ssize_t bytes_read = read(fd, array_native_ptr + offset, (size_t) count);
(*e) -> ReleaseByteArrayElements(e, array, array_native_ptr, 0);
return bytes_read;
}
分析 java 应用程序 运行 该函数显示了一些不明确的结果。这是顶部:
最热门的事情之一原来是来自 libc-2.27.so
地址 0x18eb1f
的一些指令。我想了解它是什么,但 gdb 不知道它
(gdb) disas 0x18eb1f
No function contains specified address
Objdump'ing libc grep 我发现的地址
18eb0b: 72 0f jb 18eb1c <__nss_group_lookup@GLIBC_2.2.5+0x24ddc>
[...]
18eb1c: 48 89 d1 mov %rdx,%rcx
18eb1f: f3 a4 rep movsb %ds:(%rsi),%es:(%rdi)
它看起来像是 __nss_group_lookup
的一部分,而 __nss_group_lookup
似乎不包含地址:
(gdb) disas __nss_group_lookup
Dump of assembler code for function __nss_passwd_lookup:
0x0000000000169d40 <+0>: mov rax,QWORD PTR [rip+0x281121] # 0x3eae68
0x0000000000169d47 <+7>: mov DWORD PTR fs:[rax],0x26
0x0000000000169d4e <+14>: mov eax,0xffffffff
0x0000000000169d53 <+19>: ret
End of assembler dump. making the things more unclear then it was before.
让事情变得比以前更不清楚了。
问题: 你能给出任何提示去哪里看以理解为什么属于 __nss_group_lookup
的指令是调用 jni_GetByteArrayElements
/jni_ReleaseByteArrayElements
时最热,实际上是什么。
我的预期是因为 jni_GetByteArrayElements
/jni_ReleaseByteArrayElements
通过 memcpy
将 byte[]
从 Java 堆复制到 C 堆,这将是最热的。
显然您系统上的 libc 不包含调试符号(共享库中没有 .symtab
部分)。因此 gdb 显示距离 .dynsym
最近的导出符号,这与实际最热门的函数无关。
rep movsb
指令表明此片段是 memcpy
实现的一部分。
安装 libc-dbg
包(或者它在您的 Linux 发行版中的称呼)。
例如在我的 Ubuntu 18.04 上,地址 __nss_group_lookup+0x24ddc
确实指向 memcpy
内部:
(gdb) disas __nss_group_lookup+0x24ddc
Dump of assembler code for function __memmove_avx_unaligned_erms:
0x00007ffffef7ead0 <+0>: mov %rdi,%rax
...
0x00007ffffef7eb1c <+76>: mov %rdx,%rcx
0x00007ffffef7eb1f <+79>: rep movsb %ds:(%rsi),%es:(%rdi)
0x00007ffffef7eb21 <+81>: retq