首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Android上使用strace

在Android上使用strace
EN

Stack Overflow用户
提问于 2022-08-12 07:39:38
回答 1查看 132关注 0票数 0

我一直试图使用strace来跟踪在运行用c/c++编写的本机应用程序时执行的系统调用。经过几次在“真实世界”应用上的尝试后,我意识到事情并不像在Linux上那么简单。首先,因为有更多的系统调用(这很好),但真正的问题是,我甚至可以看到我知道的系统调用,,应该在strace中弹出。

因此,我决定创建最简单的ndk应用程序,并在那里使用strace。但我看到的是同样的东西。

下面是这个简单应用程序的代码:

代码语言:javascript
运行
复制
#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.

代码语言:javascript
运行
复制
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);。这会让我们有时间去连接这个过程。这将产生与第二种方法相同的结果,但这不是您可以可靠地使用一个真实世界的应用程序。

  1. 第二种方法是基于https://stackoverflow.com/a/26610905/5969257的,看起来更完整,但仍然缺少一些东西。
代码语言:javascript
运行
复制
set `ps -A | grep -w zygote64` ; strace -p $2 -ff -tt -T -s 500 -o /storage/emulated/0/Download/strace.txt

这里的想法是将strace附加到zygote64,这将有效地促进新的进程。

例如,在logcat中我可以看到

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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有什么问题?

代码语言:javascript
运行
复制
EN

回答 1

Stack Overflow用户

发布于 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的热门方法,所以输出杂音太大了。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73330753

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档