LLDB调试安卓Native C++应用时continue触发SIGSEGV,如何正常执行?
我正在使用lldb调试一个崩溃的原生C++应用,在android_main开头添加了sleep(5),以便有时间将调试器附加到应用。附加完成后应用处于暂停状态,执行continue命令后,进程立即停止并抛出SIGSEGV信号:
(lldb) continue Process 4158 resuming Process 4158 stopped * thread #19, name = 'com.example.app', stop reason = signal SIGSEGV: invalid address (fault address: 0x0) frame #0: 0x00007cefe26282c8 -> 0x7cefe26282c8: movq (%rcx), %rdx 0x7cefe26282cb: movq %rdx, 0x18a0(%rax) 0x7cefe26282d2: movl 0x8(%rcx), %ecx 0x7cefe26282d5: movl %ecx, 0x18a8(%rax)
再次执行continue命令后,应用直接退出崩溃:
(lldb) continue Process 4158 exited with status = 11 (0x0000000b)
请问如何修复该问题,使应用能够正常继续执行?
定位空指针根源
当前SIGSEGV是因为rcx寄存器指向0x0地址,执行movq (%rcx), %rdx时访问了空指针。先执行bt命令打印完整调用栈,确认崩溃触发点是自有代码还是系统库:(lldb) bt若调用栈包含自有函数,直接定位对应代码检查空指针;若为系统库,则排查调用该库函数时传入的参数是否为空。
替换sleep为安全的调试等待逻辑
在android_main开头加sleep(5)可能打乱Android应用初始化时序——部分系统服务或全局对象可能因主线程阻塞超时,导致后续拿到空指针。可以替换为动态检查调试器是否附加的逻辑:// 替换sleep(5),等待调试器附加 while (!DebuggerIsAttached()) { usleep(100000); // 每100ms检查一次 }其中
DebuggerIsAttached()可通过Android NDK接口实现:#include <android/api-level.h> #include <android/debug.h> #include <cstdio> #include <cstring> #include <cstdlib> bool DebuggerIsAttached() { #if __ANDROID_API__ >= 28 return android_get_debugger_status() != ANDROID_DEBUGGER_STATUS_NONE; #else // 低版本通过检查/proc/self/status的TracerPid字段 FILE* fp = fopen("/proc/self/status", "r"); if (!fp) return false; char buf[256]; while (fgets(buf, sizeof(buf), fp)) { if (strstr(buf, "TracerPid:") && atoi(buf+10) != 0) { fclose(fp); return true; } } fclose(fp); return false; #endif }临时忽略信号(仅调试用)
若确认该SIGSEGV是调试环境导致的假崩溃(正常运行不会触发),可让lldb忽略该信号:(lldb) process handle -s false SIGSEGV执行后再
continue即可让应用继续运行,但这只是临时绕过,建议优先排查根本原因。检查子线程初始化依赖
崩溃发生在thread #19(非主线程),说明可能是子线程依赖的全局对象因主线程被sleep阻塞未完成初始化。可通过以下命令排查:(lldb) thread list (lldb) thread select 19 (lldb) bt确认子线程执行的代码,检查是否存在依赖主线程初始化的资源。
内容的提问来源于stack exchange,提问作者user18514618

