ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Perfetto 符号化与反混淆实战指南:从原始地址到可读函数名的完整工作流

Perfetto 符号化与反混淆实战指南:从原始地址到可读函数名的完整工作流 Perfetto 符号化与反混淆实战指南从原始地址到可读函数名的完整工作流【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfetto导读本指南围绕 Perfetto 中的Symbolization符号化与Deobfuscation反混淆展开系统讲解如何将采集到的 trace 中原始指令地址native 侧与被 R8/ProGuard 混淆的 Java/Kotlin 名称还原为人类可读的函数名、源文件与行号、类与方法名。全文按你手上的 trace 属于哪一类组织调用栈类数据源走离线trace_processor bundle流程内核 ftrace 事件必须在录制时启用symbolize_ksyms而 atrace 等用户态事件名目前无法事后还原。读完本文你将掌握两类符号解析工具链的完整用法、符号查找顺序、排错技巧以及仓库中对应的源码实现位置。核心概念符号化与反混淆是两回事在深入工作流之前先明确两个贯穿全文的定义原文档用语Symbolization符号化借助被剖析进程实际加载的未 strip 的 ELF 二进制或等价的 Breakpad 符号文件将 native 指令地址映射回函数名、源文件与行号。Deobfuscation反混淆借助构建时生成的mapping.txt将 R8/ProGuard 输出的混淆 Java/Kotlin 名称如fsd.a映射回原始标识符。两者处理的对象不同地址 vs 名称、依赖的产物不同ELF/Breakpad vsmapping.txt但常常在一条分析流水线中同时出现因此 Perfetto 提供了统一的trace_processor bundle命令一并处理。先做选择你的 trace 属于哪一类符号不生效最常见的原因就是选错了工作流。原文档给出的经验法则非常关键用户态userspace符号在宿主机离线解析由trace_processor完成而内核kernel符号必须在设备端录制时解析——Perfetto 刻意不在 trace 中存储内核绝对地址以免破坏 KASLR内核地址空间布局随机化防护。请按下表对号入座你的 trace 包含…示例你需要什么调用栈Callstacksnative heap profiler、traced_perf/ Linux perf CPU 采样、ART heap dumps符号化与反混淆。用户态帧离线解析trace_processor bundle内核帧在设备端自动符号化。内核 ftrace 事件function_graph追踪、sched_blocked_reason、kprobes录制时启用symbolize_ksyms。这些地址事后无法符号化。用户态事件名atrace slice 名称、ART method tracing当前不支持离线反混淆应在插桩时直接产出可读名称。调用栈 Callstacks 的符号化与反混淆这条工作流适用于所有捕获调用栈的数据源native heap profiler、基于 perf 的 CPU profilertraced_perf与导入的 Linuxperf数据、ART 分配 profiler。这些数据源在录制时只记录用户态原始指令地址在 Android 上还有被混淆的 Java/Kotlin 帧只要还保留匹配的二进制与 mapping 文件就无需重新录制即可在录制完成后的宿主机上离线解析出用户态符号或反混淆名称。调用栈中若混有内核帧处理方式不同见本节的内核帧小节。方式一trace_processor bundle推荐trace_processor bundle是一次性命令输入一个 trace输出一个富化后的 traceenriched trace——原始 trace 加上解析符号与反混淆所需的全部数据打包进单个文件trace_processor bundle input.perfetto-trace enriched-trace富化后的 trace 可以像普通 trace 一样在 Perfetto UI 或trace_processor_shell中打开符号与反混淆名称已自动生效。实现细节说明富化 trace 目前以TAR 归档形式打包内含原始 trace、native 符号包symbols.pb与 Java/Kotlin 反混淆包deobfuscation.pb。UI 与trace_processor_shell能透明读取该格式通常无需手动解包。这一点在 trace_to_bundle.cc 中清晰可见TraceToBundle先用TarWriter写入trace.perfetto随后依次追加symbols.pb与deobfuscation.pb。前置要求本机$PATH中有llvm-symbolizer用于 native 符号化以产出函数名与行号Debian/Ubuntu 上执行sudo apt install llvm。输入与输出必须是文件路径不支持 stdin/stdout。磁盘上存在匹配的未 strip 二进制 / Breakpad 符号Build ID 必须与设备上录制时一致。对 Java/Kotlin需要设备上那次构建产生的mapping.txt。自动路径发现auto-discovery相对传统方式的主要优势bundle无需任何配置即可在常见位置自动查找符号与 mapping 文件。它会依次搜索AOSP 构建输出在lunch之后的 AOSP checkout 内运行时查找$ANDROID_PRODUCT_OUT/symbols标准系统调试目录$HOME/.debug、/usr/lib/debugtrace 的stack_profile_mapping中记录的绝对库路径在同一台机器上剖析并分析时尤其有用标准的 Android Gradle 工程布局中的 ProGuard/R8 mapping 文件./app/build/outputs/mapping/variant/mapping.txt。这一发现逻辑在源码中有完整实现。查看 trace_enrichment.h 的注释其路径发现覆盖PERFETTO_BINARY_PATH环境变量、ANDROID_PRODUCT_OUT/symbolsAOSP 构建、Gradle 工程路径cmake、merged_native_libs、.build-id、系统调试路径/usr/lib/debug、~/.debug、PERFETTO_PROGUARD_MAP环境变量以及 Gradle ProGuard mapping 文件。而 trace-processor-cli.md 给出了自动目录的完整顺序表/usr/lib/debug→$HOME/.debug→$ANDROID_PRODUCT_OUT/symbols→./app/build/intermediates/cmake→./app/build/intermediates/merged_native_libs→./.build-id后三者相对工作目录。用 flags 补充自动发现当自动发现不够用时显式指定路径trace_processor bundle \ --symbol-paths /path/to/symbols1,/path/to/symbols2 \ --proguard-map com.example.app/path/to/mapping.txt \ --verbose \ input.perfetto-trace enriched-trace--symbol-paths指向包含匹配的未 strip 二进制或 native 调试文件的目录例如你构建输出的 symbols 目录。bundle会递归索引并按 Build ID 匹配因此无需复刻设备上的目录结构。Java/Kotlinmapping.txt通过--proguard-map单独传入可重复该 flag 传多个映射pkg前缀可选用于将映射限定到某个 Java 包。--verbose用于诊断缺失的符号。要关闭自动发现加--no-auto-symbol-paths与--no-auto-proguard-maps。注意PERFETTO_BINARY_PATH中的 native 路径仍然生效想彻底限制查找范围需要先 unset 该环境变量再仅使用--symbol-paths。完整 flag 语义、颜色控制与退出码见 trace-processor-cli.md 的 bundle 小节。其退出码约定为成功写出 bundle 即退出 0即使部分符号缺失缺失情况在摘要中报告参数非法或 bundle 产出失败才以非零退出。方式二传统trace_processor util symbolize/util deobfuscate兼容旧脚本注意此流程仅为向后兼容已有脚本与 CI 流水线而保留。新用法一律优先方式一——它更简单、有自动发现且支持非 Perfetto 格式的 trace。旧式trace_processor util symbolize与trace_processor util deobfuscate子命令完全由环境变量驱动产出独立的符号/反混淆文件需要手工拼接到 trace 上。Native 符号化所有工具trace_processor、tools/heap_profile脚本都遵守PERFETTO_BINARY_PATH环境变量PERFETTO_BINARY_PATHsomedir tools/heap_profile android --name ${NAME}为已采集的 trace 产出独立符号文件PERFETTO_BINARY_PATHsomedir trace_processor util symbolize raw-trace symbols或者设置PERFETTO_SYMBOLIZER_MODEindex符号化器会按 Build ID递归索引目录中的 ELF 文件这样文件名无需与设备一致。Java/Kotlin 反混淆通过PERFETTO_PROGUARD_MAP提供 ProGuard/R8 映射格式为packagenamemap_filename[:packagenamemap_filename...]PERFETTO_PROGUARD_MAPcom.example.pkg1foo.txt:com.example.pkg2bar.txt \ ./tools/heap_profile android -n com.example.app为现有 trace 产出独立反混淆文件PERFETTO_PROGUARD_MAPcom.example.pkgproguard_map.txt \ trace_processor util deobfuscate ${TRACE} deobfuscation_map把输出附加到 trace 上上面的symbols与deobfuscation_map都是序列化的TracePacketproto因此对Perfetto protobuf trace可以直接拼接cat ${TRACE} symbols symbolized-trace cat ${TRACE} deobfuscation_map deobfuscated-trace # 或两者都要 cat ${TRACE} symbols deobfuscation_map enriched-trace当设置了PERFETTO_BINARY_PATH时tools/heap_profile脚本会在其输出目录中自动完成上述拼接。局限性拼接技巧只对 Perfetto protobuf trace 有效。其他格式Chrome JSON、systrace、Firefox profile 等无法这样追加TracePacket字节这类格式请使用方式一并通过trace_processor_shell加载符号。PERFETTO_BINARY_PATH/PERFETTO_PROGUARD_MAP必须手工管理方式一的自动发现在这里完全不适用。符号查找顺序Symbol lookup order对 trace 中的每个 native mapping符号化器会查找 Build ID 匹配的文件。对每个搜索路径P按以下顺序尝试库文件相对于P的绝对路径。同上但从文件名中去掉base.apk!前缀。库文件相对于P的 basename。basename去掉base.apk!前缀。P/.build-id/前 2 位十六进制/其余部分.debug标准 Fedora Build ID 布局。例如build id 为abcd1234...的/system/lib/base.apk!foo.so会在符号路径P下依次查找P/system/lib/base.apk!foo.soP/system/lib/foo.soP/base.apk!foo.soP/foo.soP/.build-id/ab/cd1234...debug第一个 Build ID 匹配的文件胜出。若磁盘上的 Build ID 与 trace 记录的不一致该文件会被跳过。此外bundle对符号路径执行递归索引并按 Build ID 匹配见 trace-processor-cli.md 的 Native symbol paths 小节因此目录布局与文件名不必与 trace 中记录的路径一致对 Breakpad 符号则在每个配置目录中查找build-id.breakpadbuild ID 编码为小写十六进制。需要留意的是递归索引阶段收集路径的顺序并不代表同一 Build ID 多个副本之间的优选关系建议直接指向包含匹配未 strip/调试二进制的目录而不要混入 strip 与未 strip 的副本。从 C 库中使用符号化/反混淆目前没有稳定的公共 C API支持进程内符号化或反混淆。底层实现存在TraceToBundle位于 trace_to_bundle.h由 trace_enrichment.h 中的EnrichTrace支撑但它位于src/而非include/不属于公共 API 面。如确有需求可在 GitHub issue #5534 上 1 以表达诉求、推动排期。Troubleshooting 排错trace_processor bundle总是产出至少包含原始 trace的 bundle。当它无法完成全部富化时会打印缺失项摘要及修复方法然后仍然成功退出——所以即使命令成功也要检查输出。只有真正失败输入不可读、输出不可写、或显式提供的--proguard-map无法读取才以非零退出。这一点在 trace_to_bundle.cc 中明确实现只有EnrichmentError::kExplicitMapsFailed是硬错误其余情况均照常产出 bundle 并打印提示。常见输出信息及含义N frames could not be symbolized and will appear as unknown并带hint: use --symbol-paths ...工具搜遍了自动发现的路径加上你给的--symbol-paths仍未找到 Build ID 匹配的二进制。按提示操作或用--verbose重跑以查看每一个被尝试的路径。N frames ... no build IDs in trace, symbol lookup requires build IDstrace 的 mapping 没有 Build ID即使有正确的二进制也无法匹配。需要用带 Build ID 的二进制链接器 flag-Wl,--build-id重新构建并重新录制。Kernel function names: this trace contains function_graph events ...trace 含有来自function_graph或类似 ftrace 事件的内核地址但录制时未启用symbolize_ksyms。这些地址无法离线符号化请以symbolize_ksyms: true重新录制。见内核 ftrace 事件。no symbol paths were searched自动发现被关闭--no-auto-symbol-paths且未显式给出路径。请用--symbol-paths传入要搜索的目录。cannot create output file ...输出路径无法创建如父目录不存在或不可写。请检查路径。找不到库Could not find library带--verbose符号化 profile 时可能看到类似输出No matching symbols in searched paths for 1 mapping (12 frames): /data/app/invalid.app-wFgo3GRaod02wSvPZQ/lib/arm64/somelib.so (12 frames) build ID: 44b7138abd5957b8d0a56ce86216d478 paths searched: /path/to/symbols/somelib.so (file not found) hint: use --symbol-paths to specify symbol files or directories检查somelib.so是否存在于某个搜索路径--symbol-paths或自动发现位置之下。然后用readelf -n /path/to/somelib.so比对磁盘上的 Build ID 与消息中报告的 Build ID若不一致说明磁盘上的副本与设备上的是不同构建不能使用。用--verbose重跑trace_processor bundle会打印每个被尝试的路径通常能立刻分辨是文件完全缺失还是找到但 Build ID 不匹配。调用栈中的内核帧Kernel frames in callstacks采样调用栈可能包含内核帧例如以callstack_sampling { kernel_frames: true }进行 perf 采样。与上述用户态帧不同这些帧在录制时由设备端自动符号化数据来自/proc/kallsyms——本节中的离线工具不会触碰它们。内核帧要能命名录制进程必须能读取/proc/kallsyms这要求以 root 运行或调低kptr_restrictecho 0 | sudo tee /proc/sys/kernel/kptr_restrict如果内核帧显示为十六进制地址那是录制时的权限问题必须重新录制。这与下文内核 ftrace 事件的 KASLR 约束相同但注意两者机制不同调用栈中的内核帧不使用symbolize_ksyms这个 ftrace 选项——该 flag 只影响 ftrace 事件。内核 ftrace 事件symbolize_ksyms如果你在做系统追踪时看到本该是内核函数名的位置出现裸十六进制地址——例如 function_graph 追踪、不可中断睡眠的 调度阻塞 中的blocked_function字段、或 kprobe 事件——解决办法不是离线符号化。这些内核地址在录制时通过启用 ftrace 配置中的symbolize_ksyms解析data_sources: { config { name: linux.ftrace ftrace_config { symbolize_ksyms: true # ... 你的 ftrace_events / function_graph 配置 ... } } }这会读取设备上的/proc/kallsyms并将mangled 过的符号表嵌入 trace。前提是traced_probes以 root 运行或已手工调低kptr_restrict。funcgraph.md 也强调symbolize_ksyms: true是让每个函数显示名称而非地址的必要条件。WARNINGtrace_processor bundle及上述离线符号化工具无法恢复内核符号。Perfetto 刻意不在 trace 中存储内核绝对地址——否则会破坏 KASLR、泄露内核内存布局。符号名在设备端被 mangled从而在不泄露绝对地址的前提下完成解析。如果忘了设置symbolize_ksyms只能重新录制。该 flag只作用于 ftrace 事件。采样调用栈内部捕获的内核帧单独处理见调用栈中的内核帧。用户态事件名atrace 与 ART Method Tracing某些数据源记录的是人类可读的名称字符串而非地址或栈帧。当这些字符串被混淆例如 R8 混淆的类名时没有离线机制可以反混淆——必须在插桩时就以可读形式产出名称。这与调用栈一节中的 Java/Kotlin栈帧反混淆是两回事栈帧反混淆只适用于 heap dumps 与采样调用栈。目前受影响的有两类场景atrace / 用户态 slice 名称atrace 的 slice 名称以及落入TRACE_EVENT字面量的其他字符串原样记录没有事后映射步骤。ART method tracingART method tracing 捕获的方法名不经过 ProGuard/R8 反混淆路径因此混淆构建会显示混淆后的方法名。基于mapping.txt为这类名称做反混淆原则可行但尚未实现相关支持仍在讨论中GitHub issue #6391 有上下文可去登记诉求。源码级实现脉络速览若要深入理解本文所述工作流的底层实现可在当前仓库中按以下路径继续阅读富化入口trace_to_bundle.ccTraceToBundle负责读入 trace → 写入 TAR → 调用EnrichTrace→ 追加symbols.pb/deobfuscation.pb→ 依据EnrichmentError决定硬失败或成功返回。富化配置与执行trace_enrichment.hEnrichmentConfig完整映射了 CLI 的--symbol-paths、--proguard-map、--no-auto-*、--verbose等选项EnrichmentResult携带序列化好的native_symbols与deobfuscation_data。符号化器实现symbolizer 目录 下的llvm_symbolizer.*调用llvm-symbolizer产出函数名与行号、breakpad_symbolizer.*解析 Breakpad 符号文件、local_symbolizer.*按 Build ID 在本地目录中查找 ELF、symbolize_database.*维护符号数据库与查找顺序。集成测试traceconv_bundle_integrationtest.cc 覆盖bundle端到端行为是验证各选项语义与退出码约定的权威参考。CLI 参考trace-processor-cli.md 的bundle小节含完整参数表、自动目录顺序表与退出码说明。小结一张表记住三种场景Trace 内容解析时机手段失败后怎么办调用栈中的用户态帧录制后离线trace_processor bundle推荐或util symbolize/util deobfuscate 手工拼接用--verbose/readelf -n核对 Build ID补--symbol-paths调用栈中的内核帧录制时设备端自动从/proc/kallsyms符号化需 root 或调低kptr_restrict修权限后重新录制内核 ftrace 事件录制时设备端ftrace 配置symbolize_ksyms: true补配置后重新录制atrace / ART 方法名插桩时直接产出可读名称无离线方案讨论中见 issue #6391记住贯穿全文的那条主线用户态符号离线解内核符号只能在线解。选对工作流符号问题就解决了一大半。【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfetto创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表