[√]leak tracer的stack address始终无法被addr2line识别

简介: [√]leak tracer的stack address始终无法被addr2line识别

感谢文章:blog.csdn.net/tq08g2z/art…

使用适配过Android的leak tracer,不要使用官方的。我自己写的测试demo

注意

尽量将leak tracer编译到要检测内存泄露模块的动态库中,不要单独将leak tracer编译为一个so动态库,否则会导致addr2line无法正确识别出地址符号。

LeakTracer使用教程

在Android平台上检测内存泄露,最终选择使用leak tracer。

通过leak traker,收集到leak结果如下:

# LeakTracer report diff_utc_mono=1685323259.020343
leak, time=1562403.055277, stack=0x7921948b54 0x7921948de4 0x7921c80e00 0x7923f99460 0x792433eee0, size=10485760, data=..................................................
leak, time=1562403.055280, stack=0x7921948b54 0x7921948de4 0x7921c83df4 0x7921c81dc8 0x7921c839e0, size=8, data=....y...

使用addr2line还原调试符号

很明显,我们看到stack都是符号地址,需要通过addr2line工具还原详细的信息

llvm-addr2line.exe -C -f -e libjni.so 0x7921948b54

建议使用ndk版本对应的addr2line,不过我发现其他版本的也可以,比如我使用的是:

ndk\23.1.7779620\toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-addr2line.exe

so文件的路径:

app\build\intermediates\ndkBuild\debug\obj\local\arm64-v8a\*.so

至于使用哪个so,要看__builtin_frame_address函数所在的动态库模块

  • 如果libleaktracer是一个单独的so动态库,那么就应该使用libleaktracer.so(一般都是这种)
  • 如果libleaktracer被以静态库的方式引入到另外一个动态库,就应该使用target.so

addr2line显示??::

检查方向:

  • 确认so库的路径,以及是否携带调试符号信息

image.png

  • 确认使用的是项目编译sdk的addr2line
  • addr2line的地址参数,是否和so混用,so里面必须有该地址才能被正常识别。
  • 检查你的地址

检查你的地址

这个也是本篇文章我遇到的,0x7921948de4这种非常大的地址,一看就有问题。

每个进程都有自己独立的进程地址空间。该进程地址空间被划分为一系列连续的虚拟地址空间,每个虚拟地址对应着唯一的物理地址。

在 x86 架构的计算机中,操作系统会为每个进程分配一个虚拟地址空间,该空间从 0x00000000 到 0xFFFFFFFF(或者更少),共 4GB 的大小。

如果要使用 addr2line 工具查询动态链接库(DLL)中某个函数的源代码位置信息,通常需要将查询地址减去该 DLL 的基地址。

这是因为在 Windows 平台上,每个 DLL 都有一个基地址,用于确定该 DLL 中所有函数和变量在虚拟地址空间中的位置,以保证不同 DLL 之间的地址不会重叠冲突。

如果直接使用官方的源码,是没有处理基地址的问题,如果leak tracer以动态库的方式引入到项目,那么stakc地址是有问题的,导致你无论怎么试错,都无法得到正确的调试符号信息。

而处理这个基地址,一个非常重要的函数就是dladdr

leak traer所使用到的函数

__builtin_frame_address

void* __builtin_frame_address(unsigned int level);

GCC 内建函数之一,在 C/C++ 中使用时可以获取当前函数的堆栈帧指针(Frame Pointer)。

其中,level 参数表示向上返回堆栈帧的层级数。

如果 level 大于当前函数的堆栈帧层数,返回 NULL

有些linux系统返回的内存地址就是VMA地址

dladdr

获得指定地址所在的共享库信息,函数原型如下:

int dladdr(
    const void *addr, // 要查询的地址
    Dl_info *info     // 用于存储查询结果的结构体
);

Dl_info 结构体定义如下:

typedef struct {
    const char* dli_fname; /* 共享库文件名 */
    void* dli_fbase; /* 基地址 */
    const char* dli_sname; /* 符号名 */
    void* dli_saddr; /* 符号地址 */
} Dl_info;

dladdr 函数的返回值是非零表示查询成功,否则表示查询失败。如果查询成功,info 参数中会填充该地址所在的共享库文件名、基地址、符号名称和符号地址等信息。

示例结果:

dli_fbase: 0x791e321000, 
dli_fname:/data/app/~~M4EQtyRf9F8ogdMdo1pJEg==/com.example.jni-gHJ1rvzAUolWe7FDtjUucA==/base.apk!/lib/arm64-v8a/libjni.so, 
dli_saddr:0x791e33eb94, 
dli_sname:_Z12test_addressv

_Unwind_Backtrace

在 Android NDK 中,您可以使用 _Unwind_Backtrace 函数获取当前线程的函数调用栈信息。

目录
相关文章
|
存储 人工智能
2023 年最好的36款 AI 生产力工具(三)
简介: 本文主要展示了36 款 AI 应用,可以帮助读者更快、更好地工作。每个人都在与ChatGPT交流,从完整的博客文章到特定代码行的功能都在询问。其结果令人惊叹。虽然我们仍在探索如何将这项技术纳入我们的工作流程中,但明显的是,人工智能工具正在改变游戏规则。尽管ChatGPT是目前最受欢迎的,但它远不是首款进入市场的人工智能应用程序。经过Zapier团队的大量研究和测试,总结出了以下36款能够改变工作方式的人工智能生产力工具。
311 1
|
缓存 NoSQL 安全
Linux设备驱动程序(四)——调试技术3
Linux设备驱动程序(四)——调试技术3
430 0
|
存储 Java 测试技术
记一次堆内外内存问题的排查和优化
记一次堆内外内存问题的排查和优化
850 0
|
弹性计算 负载均衡 监控
防御DDoS攻击:策略与技术深度解析
【6月更文挑战第12天】本文深入探讨了防御DDoS攻击的策略和技术。DDoS攻击通过僵尸网络耗尽目标系统资源,特点是分布式、高流量和隐蔽性。防御策略包括监控预警、流量清洗、负载均衡、弹性伸缩及灾备恢复。技术手段涉及IP信誉系统、深度包检测、行为分析、流量镜像与回放及云防护服务。综合运用这些方法能有效提升抗DDoS攻击能力,保障网络安全。
[√]addr2line
[√]addr2line
398 0
|
设计模式 安全 Java
程序与技术分享:Context详解
程序与技术分享:Context详解
596 0
|
Kubernetes Linux UED
在Linux中,什么是滚动更新和静态更新?
在Linux中,什么是滚动更新和静态更新?
|
前端开发 网络协议
Nest.js 实战 (十四):如何获取客户端真实 IP
这篇文章介绍了在Nest.js应用中获取客户端真实IP地址的问题及解决方法。问题出现在使用本地代理时,请求的IP地址总是返回::1或::ffff:127.0.0.1。为解决这个问题,需要确保代理服务器正确设置转发头如X-Forwarded-For或X-Real-IP,后端服务能够读取这些头信息来确定客户端的IP地址。文章以作者自己的OpenResty应用为例,展示了如何通过配置反向代理和设置X-Forwarded-For头来获取真实IP地址,并提供了相关的代码示例。最后,文章提到了使用这个解决方案后的实际效果,例如在操作日志中记录真实IP地址。
494 0
|
Java Android开发
修改Android 触摸提示音及音量大小
修改Android 触摸提示音及音量大小
693 4
|
定位技术 开发者
高德地图开发 —— 获取高德地图开发的 key
高德地图开发 —— 获取高德地图开发的 key
1159 0

热门文章

最新文章