下巴长痘痘是什么原因,深化了解Android NDK日志符号化,广告赚钱

频道:最近大事件 日期: 浏览:257

CSDN移动将继续为您优选移动开发的精华内容,一同评论移动开发的技能热点话题,包括移动运用、开发东西、移动游戏及引擎、智能硬件、物联网等三国之常胜侯方方面面。假如您想投稿、参加内容翻译作业,或寻求近匠报导,请发送邮件至tangxy#csdn.net(请把#改成@)。

前语

为了进行代码及产品维护,简直一切的非开源App都会进行代码混杂。这样,当收集到溃散信息后,就需求进行符号化来复原代码信息,以便开发者能够定位Bug。根据运用SDK和NDK的不同,Android的溃散分为两类:Java溃散和C/C++溃散。Java溃散经过mapping.txt文件进行符号化,比较简单直观。而C/C++溃散的符号化则需求运用Google自带的一些NDK东西,比方ndk-stack、addr2line、objdump等。本文不去评论怎么运用这些东西,有爱好的朋友能够参阅之前尹春鹏写的另一篇文章《 怎么定位Android NDK开发中遇到的过错》,里边做了详细的描绘。

根据NDK的Android开发都会生成一个动态链接库(so),它是根据C/C++编译生成的。动态链接库在Linux体系下广泛运用,而Android体系底层是根据Linux的,所以NDK so库的编译生成遵从相同的规矩,只不过米奇拼图Google NDK把相关的穿插编译东西都封装了。

Ndk-build编译时会生成的两个同名的so库,坐落不同的目录/project path/libs/armeabi/xxx.so和/project path/obj/local/armeabi/xxx.so,比较两个so文件会发现体积相差很大。前者会跟从App一同发布,所以尽可能地小,而后者包括了许多调试信息,首要为了gdb调试的时分运用,当然,NDK的日志符号化信息也包括其间。

深入剖析so动态库组成结构

本文首要针对这个包括调试信息的so动态库,深入剖析它的组成结构。在开端之前,先来说说这样做的意图或许优点。现在的App根本都会收集上报溃散时的日志信息,无论是选用第三方云渠道,仍是自己建立醇酯十二成膜助剂云效劳,都要将含调试信息的so动态库上传,完成云端日志符号化以及云端可视化办理。

移动App的快速迭代,使得咱们有必要存储办理每一个版别的debug so库,而其包括了许多与符号化无关的信息。假如咱们只提取出符号化需求的信息,那么符号化文件的体积将会出现数量级的削减。一起能够在自界说的符号化文件中增加App的版别号等定制化信息,完成符号化提取、上传到云端、云端解析及可视化等自动化布置。别的,从技能视点讲,开发者将不再惧怕看到“unresolved symbol” linking errors,能够更沉着地debugging C/C++ crash或进行一些hacking操作。

首要经过readelf来看看两个不同目录下的so库有什么不同。

从中能够清楚看到,包括调试信息的so库多了8个.debug_最初的条目以及.symtab和.strtab条目。符号化的实质,是经过仓库中的地址信息,复原代码原本的句子以及相应的行号,所以这儿只需解析.debug_ line和.symtab,终究获取到如下的信息就能够完成符号化了。

c85 c8b willCrash jni/hello-jni.c:27-29 c8b c8d willCrash jni/hello-jni.c:32 c8d c8f JNI_ jni/hello-jni.c:34 c8f c93 JNI_ jni/hello-jni.c:35 c93 c9d JNI_ jni/hello-jni.c:37gayandguy

一般,方针文件分为三类:relocatable文件、executable文件和shared object文件,它们格局称为ELF(Executable and Linking Format),so动态库归于第三类shared object,它的全体安排结构如下:

ELF Header

ELF Header文件头的结构如下,记录了文件其他内容在文件中的偏移以及陈怀远巨细信息。这儿以32bit为例:

typedef struct { unsigned ch下巴长痘痘是什么原因,深化了解Android NDK日志符号化,广告挣钱ar e_ident[EI_NIDENT]; Elf32_Half e_type; // 方针文件类型,如relocatable、executable和shared object Elf32_Half e_machine; // 指定需求的特定架构,如Intel 80386,Motorol下巴长痘痘是什么原因,深化了解Android NDK日志符号化,广告挣钱a 68000 Elf32_Word e_version; // 方针文件版别,通e_ident中的EI_VERSION Elf32_Addr e_entry; // 下巴长痘痘是什么原因,深化了解Android NDK日志符号化,广告挣钱指定进口点地址,如C可执行文件的进口是_start(),而不是main() Elf32_Off e_ph万人骑与万人敌off; // program header table 的偏移量 Elf32_Off e_shoff; // section header table的偏移量 Elf32_Word e_flags; // 处理器相关的标志 Elf32_Half e_ehsize; // 代表ELF Header部分的巨细 Elf32_Half e_phentsize; // program header table中每一项的巨细 Elf32_Half e_phnum; // program header table包括多少项 Elf32_Half e_三国杀妖将shentsize; // section header table中每一项的巨细 Elf32_Half e_shnum; // section header table包括多少项 Elf32_Half e_shstrndx; //section header table中某一子项的index,该子项包括了一切section的字符串称号 进贡娘娘} Elf32_Ehdr;

其间e_ident为固定16个字节巨细的数组,称为ELF Identification,包括了处理器类型、文件编码格局、机器类型等,详细结构如下:

Sections

该部分包括了除ELF Header、program header table以及section header table之外的一切信息。经过section header table能够找到每一个section的根本信息,如称号、类型、偏移量等。

先来看看Secti严鸿化装校园on Header的内容,仍以32-bit为例:

typedef struct { Elf32_Word sh_name; // 指定sect下巴长痘痘是什么原因,深化了解Android NDK日志符号化,广告挣钱ion的斗宝斋称号,该值为String Table字符串表中的索引 Elf32_Word sh_type; // 指定section的分类 Elf32_Word sh_flags; // 该字段的bit代表不同的section特点 Elf32_Addr sh_addr; // 假如section出现在内存镜像中,该字段标明section第一个字节的地址 Elf32_Off sh_offset; // 指定section在文件中的偏移量 Elf32_Word sh_size; // 指定section占用的字节巨细 Elf32_Word sh_link; // 相关联的section header table的index Elf32_Word sh_info; // 附加信息,含义依赖于section的类型 Elf32_Word sh_addralign; // 指定地址对其束缚 Elf32_Word sh_entsize; // 假如section包括一个table,该值指定table中每一个子项的巨细 } Elf32_Shdr;

经过Section Header的sh_name能够找到指定的section,比方.debug_line、.symbol、.strtab。

String Table

String Table包括一系列以\0完毕的字符序列,终究一个字节设置为\0,标明一切字符序列的完毕,比方:

String Table也归于section,只不过它的偏移量直接在ELF Header中的e_shstrndx字段指定。String Table的读取办法是,从指定的index开端,直到遇到休止符。比方要section header中sh_name获取section的称号,假定sh_name = 7, 则从string table字节省的第7个index开端(留意这儿从0开端),一向读到第一个休止符(index=18),读取到的称号为.debug_line。

Symbol Table

该部分包括了程序符号化的界说相关信息,比方函数界说、变量界说等,每一项的界说如下:

# Symbol Table Entry typ漫漫总攻路edef struct { Elf32_Word st_name; //symbol字符串表的索引 Elf32_Addr st_value; //symbol相关的值,依赖于symbol的类型 Elf32_Word st_size; //symbol内容的巨细 unsigned char st_info; //symbol的类型及其特点 unsigned char st_other; //symbol的可见性,比方类的public等特点 Elf32_Half st_shn小小懒虫在异世dx; //与此symbol相关的section header的索引 } Elf32_Sym;

Symbol的类型包括以下几种:

其间STT_FUNC就是咱们要找的函数symbol。然后经过st_name从symbol字符串表中获取到相应的函数名(如JNI_)。当symbol类型为STT_FUNC时,st_value代表该symbol的开始地址,而(st_value+st_size)代表该symbol的完毕地址。

回忆之前说到的.symtab和.strtab两个部分,对应的就是Symbol Section和Symbol String Section。

DWARF(Debugging With Attributed Record Formats)

DWARF是一种调试文件格局,许多编译器和调试器都经过它进行源码调试(gdb等)。尽管它下巴长痘痘是什么原因,深化了解Android NDK日志符号化,广告挣钱是一种独电视直销史蒂夫净水器立的方针文件格局,但往往嵌入在ELF文件中。前面经过readelf看到的8个.debug_* Section悉数六合天地芯都归于DWARF格局。本文将只评论与符号化相关的.下巴长痘痘是什么原因,深化了解Android NDK日志符号化,广告挣钱debug_line部分,更多的DWARF信息请检查参阅文献的内容。

.debug_line部分包括了行号信息,经过它能够将代码句子和机器指令地址对应,然后进行源码调试。.debug_line由许多子项组成,每个子项都包括相似数据块头的描绘,弗萨卡称为苏引华钱是这样赚的Statement Program Prologue。Prologue供给了解码程序指令和跳转到其他句子的信息,它包榆绿毛萤叶甲含如下字段,这些字段是以二进制格局次序存在的:

这儿用到的机器指令能够分为三类:

这儿不做机器指令的解析阐明,感爱好的,能够检查参阅文献的内容。

经过.debug_line,咱们终究能够取得如下信息:文件途径、文件名、行号以及开始地址。

终究,咱们汇华山漫空栈道灵异事情总一下整个符号化提取的进程:

从ELF Header中获悉3下巴长痘痘是什么原因,深化了解Android NDK日志符号化,广告挣钱2bit或许64bit,以及大端仍是小端,根据此读取后边的内容;从ELF Header中取得Section Header Table在文件中的方位;读取Section Header Table,从中取得.debug_line、.symtab以及.strtab三个section在文中的方位;读取.symtab和.strtab两个section,终究取得一切function symbol的称号、开始地址以及完毕地址;读取.debug_line,依照DWARF格局解析获取文件称号、途径、行号以及开始地址;比照过程4和5中获取的成果,进行比照兼并,构成终究的成果。

参阅文献

作者简介:

贾志凯 Testin技能总监,首要担任溃散剖析项目Android渠道架构规划、性能及稳定性优化。 汉宫玉珑

第一时间把握最新移动开发相关信息和技能,请重视mobilehub大众微信号(ID: mobilehub)。