[√]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 函数获取当前线程的函数调用栈信息。

目录
相关文章
|
并行计算 异构计算
CUDA stream利用CUDA流重叠计
CUDA stream利用CUDA流重叠计
1194 0
CUDA stream利用CUDA流重叠计
|
存储 Java 测试技术
记一次堆内外内存问题的排查和优化
记一次堆内外内存问题的排查和优化
1069 0
|
安全 Linux 数据安全/隐私保护
CentOS中SELinux的禁用与关闭操作
在禁用SELinux时,你要时刻谨慎小心。SELinux提供了安全功能,并阻止了许多常见的网络攻击,关闭它可能会让你的系统置于风险之中。除非非常确定SELinux为你带来了不必要的麻烦,否则最好的选择往往是留着它,适当地调整和细化你的SELinux策略,来适应你的需求。
1206 19
[√]addr2line
[√]addr2line
558 0
|
弹性计算 负载均衡 监控
防御DDoS攻击:策略与技术深度解析
【6月更文挑战第12天】本文深入探讨了防御DDoS攻击的策略和技术。DDoS攻击通过僵尸网络耗尽目标系统资源,特点是分布式、高流量和隐蔽性。防御策略包括监控预警、流量清洗、负载均衡、弹性伸缩及灾备恢复。技术手段涉及IP信誉系统、深度包检测、行为分析、流量镜像与回放及云防护服务。综合运用这些方法能有效提升抗DDoS攻击能力,保障网络安全。
1006 1
|
SQL 数据可视化 atlas
用DataV Atlas探索杭州美食
本指南介绍如何使用DataV Atlas进行数据可视化。首先,通过链接领取试用额度并登录产品控制台。控制台包含示例数据,如“hangzhou_poi_sample”和“hangzhou_districts”。通过简单几步创建地理分析项目,可对数据进行样式配置。示例分析包括各区美食偏好、高评分火锅店定位及杭州美食分布情况,通过SQL查询和可视化技术,帮助理解数据背后的有趣现象。更改底图样式和添加SQL数据源进一步增强分析效果。
573 2
|
数据库管理
Dify On DMS 产品能力与案例介绍
Dify On DMS 产品能力与案例介绍
|
Kubernetes Linux UED
在Linux中,什么是滚动更新和静态更新?
在Linux中,什么是滚动更新和静态更新?
|
Linux
嵌入式 Linux下修改MAC地址
Linux下修改MAC地址 方法一: 1.关闭网卡设备ifconfig eth0 down2.修改MAC地址ifconfig eth0 hw ether MAC地址3.重启网卡ifconfig eth0 up 方法二:以上方法一修改后linux重启后MAC又恢复为原来的,为了下次启动时修改后的MAC仍有效,我们可以修改文件file:/etc/rc.
4325 0
|
数据处理 Apache 流计算
Flink报错问题之Flink报错Waiting for a cluster to become ready如何解决
Flink报错通常是指在使用Apache Flink进行实时数据处理时遇到的错误和异常情况;本合集致力于收集Flink运行中的报错信息和解决策略,以便开发者及时排查和修复问题,优化Flink作业的稳定性。