我一直试图使用strace
来跟踪在运行用c/c++编写的本机应用程序时执行的系统调用。经过几次在“真实世界”应用上的尝试后,我意识到事情并不像在Linux上那么简单。首先,因为有更多的系统调用(这很好),但真正的问题是,我甚至可以看到我知道的系统调用,,,应该在strace中弹出。
因此,我决定创建最简单的ndk应用程序,并在那里使用strace
。但我看到的是同样的东西。
下面是这个简单应用程序的代码:
#include <jni.h>
#include <string>
#include <android/log.h>
#include <signal.h>
#include <sys/mman.h>
#include <unistd.h>
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "LOG_TAG", __VA_ARGS__)
const size_t size = 4 * 1024;
static void sigsegv_handler(int id, siginfo_t *info, void *data)
{
LOGE("%s()\n", __func__);
LOGE("fault address: %p\n", info->si_addr);
mprotect(info->si_addr, size, PROT_READ | PROT_WRITE);
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
// sleep(2);
LOGE("%s()\n", __func__);
LOGE("sigsegv_handler: %p\n", sigsegv_handler);
struct sigaction sa = {};
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGSEGV);
sa.sa_sigaction = sigsegv_handler;
int result = sigaction(SIGSEGV, &sa, NULL);
if (result == -1)
LOGE("sigaction failed\n");
void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED)
LOGE("mmap failed\n");
mprotect(addr, size, PROT_NONE);
int *segfault = (int *)addr;
*segfault = 0;
const std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
我的第一个问题是,哪一种方式正确地附加到应用程序?我尝试过两种方法,但似乎都没有给出正确的结果。
1.
am start -n com.example.myapplication/com.example.myapplication.MainActivity && set `ps -A | grep myapplication` && strace -p $2 &> /storage/emulated/0/Download/strace.txt
这会产生一些结果,但肯定是不完整的,因为例如,当分段错误触发时,我看不到安装处理程序的rt_sigaction
或--- SIGSEGV
。
一个解决办法是不推荐// sleep(2);
。这会让我们有时间去连接这个过程。这将产生与第二种方法相同的结果,但这不是您可以可靠地使用一个真实世界的应用程序。
set `ps -A | grep -w zygote64` ; strace -p $2 -ff -tt -T -s 500 -o /storage/emulated/0/Download/strace.txt
这里的想法是将strace附加到zygote64
,这将有效地促进新的进程。
例如,在logcat中我可以看到
08-12 09:23:48.844 8945 8945 E LOG_TAG : Java_com_example_myapplication_MainActivity_stringFromJNI()
08-12 09:23:48.845 8945 8945 E LOG_TAG : sigsegv_handler()
08-12 09:23:48.845 8945 8945 E LOG_TAG : fault address: 0x75588af000
在strace.txt.8945
里
09:23:48.844871 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x75588af000 <0.000023>
09:23:48.844928 mprotect(0x75588af000, 4096, PROT_NONE) = 0 <0.000016>
09:23:48.844975 --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0x75588af000} ---
这很好,但是安装处理程序的rt_sigaction
调用缺失了!
所以我的问题是。我做错了什么吗?我是不是有错误的期望?还是安卓上的strace
有什么问题?
发布于 2022-08-12 18:01:48
你想要一个包装外壳脚本。使用这些方法有些烦人,但您可以以https://github.com/DanAlbert/strace-example为例。
(如果希望调试器继续工作,还应该将$NDK/wrap.sh/asan.sh
的jdwp部分从最新的wrap.sh复制到您的wrap.sh中)
然后,strace输出应该显示在logcat中。
你马上就会注意到,Android应用程序的暂停输出非常嘈杂。艺术就是在后台做大量的事情。您需要使用-e
来筛选要监视的系统。如果ART也在使用这些系统,strace基本上是无用的,您最好使用普通的旧日志。这就是我遇到的问题,因为我试图发现死锁,但由于ART一直在分析应用程序的Java端,以找到到JIT的热门方法,所以输出杂音太大了。
https://stackoverflow.com/questions/73330753
复制相似问题