博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
art 收集
阅读量:2457 次
发布时间:2019-05-11

本文共 90536 字,大约阅读时间需要 301 分钟。

介绍

想要了解ART,必须先OAT文件格式,。

再描述一下OAT是由ART中的经过dex2oat生成的一个ELF格式的文件,名字却延续DVM中的命名方式,以.dex做扩展名。

虽然是ELF,在使用的过程中确不是直接运行,而是被Map到内存中调用,有点类式SO的使用过程

在系统源码中有代码注释为:

[cpp]
  1. bool ElfWriterQuick::Write(OatWriter& oat_writer,  
  2.                            const std::vector<const DexFile*>& dex_files_unused,  
  3.                            const std::string& android_root_unused,  
  4.                            bool is_host_unused) {  
  5.   const bool debug = false;  
  6.   // +-------------------------+   
  7.   // | Elf32_Ehdr              |   
  8.   // +-------------------------+   
  9.   // | Elf32_Phdr PHDR         |   
  10.   // | Elf32_Phdr LOAD R       | .dynsym .dynstr .hash .rodata   
  11.   // | Elf32_Phdr LOAD R X     | .text   
  12.   // | Elf32_Phdr LOAD RW      | .dynamic   
  13.   // | Elf32_Phdr DYNAMIC      | .dynamic   
  14.   // +-------------------------+   
  15.   // | .dynsym                 |   
  16.   // | Elf32_Sym  STN_UNDEF    |   
  17.   // | Elf32_Sym  oatdata      |   
  18.   // | Elf32_Sym  oatexec      |   
  19.   // | Elf32_Sym  oatlastword  |   
  20.   // +-------------------------+   
  21.   // | .dynstr                 |   
  22.   // | \0                      |   
  23.   // | oatdata\0               |   
  24.   // | oatexec\0               |   
  25.   // | oatlastword\0           |   
  26.   // | boot.oat\0              |   
  27.   // +-------------------------+   
  28.   // | .hash                   |   
  29.   // | Elf32_Word nbucket = 1  |   
  30.   // | Elf32_Word nchain  = 3  |   
  31.   // | Elf32_Word bucket[0] = 0|   
  32.   // | Elf32_Word chain[0]  = 1|   
  33.   // | Elf32_Word chain[1]  = 2|   
  34.   // | Elf32_Word chain[2]  = 3|   
  35.   // +-------------------------+   
  36.   // | .rodata                 |   
  37.   // | oatdata..oatexec-4      |   
  38.   // +-------------------------+   
  39.   // | .text                   |   
  40.   // | oatexec..oatlastword    |   
  41.   // +-------------------------+   
  42.   // | .dynamic                |   
  43.   // | Elf32_Dyn DT_SONAME     |   
  44.   // | Elf32_Dyn DT_HASH       |   
  45.   // | Elf32_Dyn DT_SYMTAB     |   
  46.   // | Elf32_Dyn DT_SYMENT     |   
  47.   // | Elf32_Dyn DT_STRTAB     |   
  48.   // | Elf32_Dyn DT_STRSZ      |   
  49.   // | Elf32_Dyn DT_NULL       |   
  50.   // +-------------------------+   
  51.   // | .shstrtab               |   
  52.   // | \0                      |   
  53.   // | .dynamic\0              |   
  54.   // | .dynsym\0               |   
  55.   // | .dynstr\0               |   
  56.   // | .hash\0                 |   
  57.   // | .rodata\0               |   
  58.   // | .text\0                 |   
  59.   // | .shstrtab\0             |   
  60.   // +-------------------------+   
  61.   // | Elf32_Shdr NULL         |   
  62.   // | Elf32_Shdr .dynsym      |   
  63.   // | Elf32_Shdr .dynstr      |   
  64.   // | Elf32_Shdr .hash        |   
  65.   // | Elf32_Shdr .text        |   
  66.   // | Elf32_Shdr .rodata      |   
  67.   // | Elf32_Shdr .dynamic     |   
  68.   // | Elf32_Shdr .shstrtab    |   
  69.   // +-------------------------+   
  70.   
  71.   // phase 1: computing offsets   
  72.   uint32_t expected_offset = 0;  
bool ElfWriterQuick::Write(OatWriter& oat_writer,                           const std::vector
& dex_files_unused, const std::string& android_root_unused, bool is_host_unused) { const bool debug = false; // +-------------------------+ // | Elf32_Ehdr | // +-------------------------+ // | Elf32_Phdr PHDR | // | Elf32_Phdr LOAD R | .dynsym .dynstr .hash .rodata // | Elf32_Phdr LOAD R X | .text // | Elf32_Phdr LOAD RW | .dynamic // | Elf32_Phdr DYNAMIC | .dynamic // +-------------------------+ // | .dynsym | // | Elf32_Sym STN_UNDEF | // | Elf32_Sym oatdata | // | Elf32_Sym oatexec | // | Elf32_Sym oatlastword | // +-------------------------+ // | .dynstr | // | \0 | // | oatdata\0 | // | oatexec\0 | // | oatlastword\0 | // | boot.oat\0 | // +-------------------------+ // | .hash | // | Elf32_Word nbucket = 1 | // | Elf32_Word nchain = 3 | // | Elf32_Word bucket[0] = 0| // | Elf32_Word chain[0] = 1| // | Elf32_Word chain[1] = 2| // | Elf32_Word chain[2] = 3| // +-------------------------+ // | .rodata | // | oatdata..oatexec-4 | // +-------------------------+ // | .text | // | oatexec..oatlastword | // +-------------------------+ // | .dynamic | // | Elf32_Dyn DT_SONAME | // | Elf32_Dyn DT_HASH | // | Elf32_Dyn DT_SYMTAB | // | Elf32_Dyn DT_SYMENT | // | Elf32_Dyn DT_STRTAB | // | Elf32_Dyn DT_STRSZ | // | Elf32_Dyn DT_NULL | // +-------------------------+ // | .shstrtab | // | \0 | // | .dynamic\0 | // | .dynsym\0 | // | .dynstr\0 | // | .hash\0 | // | .rodata\0 | // | .text\0 | // | .shstrtab\0 | // +-------------------------+ // | Elf32_Shdr NULL | // | Elf32_Shdr .dynsym | // | Elf32_Shdr .dynstr | // | Elf32_Shdr .hash | // | Elf32_Shdr .text | // | Elf32_Shdr .rodata | // | Elf32_Shdr .dynamic | // | Elf32_Shdr .shstrtab | // +-------------------------+ // phase 1: computing offsets uint32_t expected_offset = 0;

介绍了生成ELF的具体格式及生成的方法,完全是代码组装,非编译器生成。

从IDA打开后,确实看到exports:

实际除了ELF标准的一些信息外,对ART使用只关注这个导出符号的数据。

三个符号可以计算出二段数据

otadata 只读相间产

otaexec 把Dalvik的Bytecode编译生成的二进制可执行数据

oatlastword 用来确定结尾

:oatdata 包括一段完整的DEX数据

oatdata 数据格式:

在源码中 art/compiler/oat_write.h 中有一段代码:

[cpp]
  1. /* 
  2.  * Copyright (C) 2011 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. #ifndef ART_COMPILER_OAT_WRITER_H_   
  18. #define ART_COMPILER_OAT_WRITER_H_   
  19.   
  20. #include <stdint.h>   
  21.   
  22. #include <cstddef>   
  23.   
  24. #include "driver/compiler_driver.h"   
  25. #include "mem_map.h"   
  26. #include "oat.h"   
  27. #include "mirror/class.h"   
  28. #include "safe_map.h"   
  29. #include "UniquePtr.h"   
  30.   
  31. namespace art {  
  32.   
  33. class OutputStream;  
  34.   
  35. // OatHeader         variable length with count of D OatDexFiles   
  36. //   
  37. // OatDexFile[0]     one variable sized OatDexFile with offsets to Dex and OatClasses   
  38. // OatDexFile[1]   
  39. // ...   
  40. // OatDexFile[D]   
  41. //   
  42. // Dex[0]            one variable sized DexFile for each OatDexFile.   
  43. // Dex[1]            these are literal copies of the input .dex files.   
  44. // ...   
  45. // Dex[D]   
  46. //   
  47. // OatClass[0]       one variable sized OatClass for each of C DexFile::ClassDefs   
  48. // OatClass[1]       contains OatClass entries with class status, offsets to code, etc.   
  49. // ...   
  50. // OatClass[C]   
  51. //   
  52. // padding           if necessary so that the following code will be page aligned   
  53. //   
  54. // CompiledMethod    one variable sized blob with the contents of each CompiledMethod   
  55. // CompiledMethod   
  56. // CompiledMethod   
  57. // CompiledMethod   
  58. // CompiledMethod   
  59. // CompiledMethod   
  60. // ...   
  61. // CompiledMethod   
  62. //   
  63. class OatWriter {  
/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#ifndef ART_COMPILER_OAT_WRITER_H_#define ART_COMPILER_OAT_WRITER_H_#include 
#include
#include "driver/compiler_driver.h"#include "mem_map.h"#include "oat.h"#include "mirror/class.h"#include "safe_map.h"#include "UniquePtr.h"namespace art {class OutputStream;// OatHeader variable length with count of D OatDexFiles//// OatDexFile[0] one variable sized OatDexFile with offsets to Dex and OatClasses// OatDexFile[1]// ...// OatDexFile[D]//// Dex[0] one variable sized DexFile for each OatDexFile.// Dex[1] these are literal copies of the input .dex files.// ...// Dex[D]//// OatClass[0] one variable sized OatClass for each of C DexFile::ClassDefs// OatClass[1] contains OatClass entries with class status, offsets to code, etc.// ...// OatClass[C]//// padding if necessary so that the following code will be page aligned//// CompiledMethod one variable sized blob with the contents of each CompiledMethod// CompiledMethod// CompiledMethod// CompiledMethod// CompiledMethod// CompiledMethod// ...// CompiledMethod//class OatWriter {

大致能说明这段数组中的格式为:

OatHeader

OatDexFile 多个

Dex 多个

OatClass 多个

下面的 CompiledMethod,属于oatexec段的

oatexec 数据格式:

上面说到,有多个 CompiledMethod组成

每个CompiledMethod的格式初步解析是这样构成的:

  1. 32位的thumb-2指令大小
  2. thumb-2指令,共上面大小
  3. mapping_table 数据
  4. vmap_table 数据
  5. gc_map 数据
  6. 对齐8字节

下面的3-5数据具体作用还末分析

010模版编写

有了格式,最好就是弄一个二进制格式的分析,为以后留用,先上一张图,再分享模版文件

模版代码:

[cpp]
  1. //-----------------------------------   
  2. //--- 010 Editor v2.0 Binary Template   
  3. //   
  4. // File:     OATTemplate.bt   
  5. // Author:   tomken   
  6. // Revision: 1.0   
  7. // Purpose:  Defines a template for   
  8. //    parsing OAT files.   
  9. //-----------------------------------   
  10.   
  11. LittleEndian();  
  12.   
  13. #define NO_INDEX (0xFFFFFFFF)   
  14.   
  15. typedef uint32 Elf32_Addr; // Program address   
  16. typedef uint32 Elf32_Off;  // File offset   
  17. typedef uint16 Elf32_Half;  
  18. typedef uint32 Elf32_Word;  
  19. typedef int Elf32_Sword;  
  20.   
  21. // Object file magic string.   
  22. // static const char ElfMagic[] = { 0x7f, 'E', 'L', 'F', '\0' };   
  23.   
  24. // e_ident size and indices.   
  25. typedef enum <uint32> {  
  26.   EI_MAG0      = 0,       // File identification index.   
  27.   EI_MAG1      = 1,       // File identification index.   
  28.   EI_MAG2      = 2,       // File identification index.   
  29.   EI_MAG3      = 3,       // File identification index.   
  30.   EI_CLASS    = 4,        // File class.   
  31.   EI_DATA      = 5,       // Data encoding.   
  32.   EI_VERSION    = 6,          // File version.   
  33.   EI_OSABI    = 7,        // OS/ABI identification.   
  34.   EI_ABIVERSION = 8,          // ABI version.   
  35.   EI_PAD        = 9,          // Start of padding bytes.   
  36.   EI_NIDENT  = 16         // Number of bytes in e_ident.   
  37. } EI_Type;  
  38.   
  39. typedef struct {  
  40.   unsigned char e_ident[EI_NIDENT]; // ELF Identification bytes   
  41.   Elf32_Half    e_type;   // Type of file (see ET_* below)   
  42.   Elf32_Half    e_machine;   // Required architecture for this file (see EM_*)   
  43.   Elf32_Word    e_version;   // Must be equal to 1   
  44.   Elf32_Addr    e_entry;     // Address to jump to in order to start program   
  45.   Elf32_Off  e_phoff;    // Program header table's file offset, in bytes   
  46.   Elf32_Off  e_shoff;    // Section header table's file offset, in bytes   
  47.   Elf32_Word    e_flags;     // Processor-specific flags   
  48.   Elf32_Half    e_ehsize;   // Size of ELF header, in bytes   
  49.   Elf32_Half    e_phentsize; // Size of an entry in the program header table   
  50.   Elf32_Half    e_phnum;     // Number of entries in the program header table   
  51.   Elf32_Half    e_shentsize; // Size of an entry in the section header table   
  52.   Elf32_Half    e_shnum;     // Number of entries in the section header table   
  53.   Elf32_Half    e_shstrndx;  // Sect hdr table index of sect name string table   
  54. } Elf32_Ehdr;  
  55.   
  56. // Segment types.   
  57. enum {  
  58.   PT_NULL   = 0, // Unused segment.   
  59.   PT_LOAD   = 1, // Loadable segment.   
  60.   PT_DYNAMIC = 2, // Dynamic linking information.   
  61.   PT_INTERP  = 3, // Interpreter pathname.   
  62.   PT_NOTE   = 4, // Auxiliary information.   
  63.   PT_SHLIB   = 5, // Reserved.   
  64.   PT_PHDR   = 6, // The program header table itself.   
  65.   PT_TLS     = 7, // The thread-local storage template.   
  66.   PT_LOOS   = 0x60000000, // Lowest operating system-specific pt entry type.   
  67.   PT_HIOS   = 0x6fffffff, // Highest operating system-specific pt entry type.   
  68.   PT_LOPROC  = 0x70000000, // Lowest processor-specific program hdr entry type.   
  69.   PT_HIPROC  = 0x7fffffff, // Highest processor-specific program hdr entry type.   
  70.   
  71.   // x86-64 program header types.   
  72.   // These all contain stack unwind tables.   
  73.   PT_GNU_EH_FRAME  = 0x6474e550,  
  74.   PT_SUNW_EH_FRAME = 0x6474e550,  
  75.   PT_SUNW_UNWIND   = 0x6464e550,  
  76.   
  77.   PT_GNU_STACK  = 0x6474e551, // Indicates stack executability.   
  78.   PT_GNU_RELRO  = 0x6474e552, // Read-only after relocation.   
  79.   
  80.   // ARM program header types.   
  81.   PT_ARM_ARCHEXT = 0x70000000, // Platform architecture compatibility info   
  82.   // These all contain stack unwind tables.   
  83.   PT_ARM_EXIDX   = 0x70000001,  
  84.   PT_ARM_UNWIND  = 0x70000001  
  85. };  
  86.   
  87. string ReadPhdrType(Elf32_Word flag) {  
  88.     switch (flag) {  
  89.         case PT_NULL:   return "null";  
  90.         case PT_LOAD:   return "load";  
  91.         case PT_DYNAMIC: return "dynamic";  
  92.         case PT_INTERP:  return "interp";  
  93.         case PT_NOTE:   return "note";  
  94.         case PT_SHLIB:   return "shlib";  
  95.         case PT_PHDR:   return "phdr";  
  96.         case PT_TLS:     return "tls";  
  97.         case PT_LOOS:   return "loos";  
  98.         case PT_HIOS:   return "hios";  
  99.         case PT_LOPROC:  return "loproc";  
  100.         case PT_HIPROC:  return "hiproc";  
  101.     }  
  102.     return "ERROR";  
  103. }  
  104.   
  105. // Program header for ELF32.   
  106. typedef struct {  
  107.   Elf32_Word p_type <read=ReadPhdrType>; // Type of segment   
  108.   Elf32_Off  p_offset; // File offset where segment is located, in bytes   
  109.   Elf32_Addr p_vaddr;  // Virtual address of beginning of segment   
  110.   Elf32_Addr p_paddr;  // Physical address of beginning of segment (OS-specific)   
  111.   Elf32_Word p_filesz; // Num. of bytes in file image of segment (may be zero)   
  112.   Elf32_Word p_memsz;  // Num. of bytes in mem image of segment (may be zero)   
  113.   Elf32_Word p_flags;  // Segment flags   
  114.   Elf32_Word p_align;  // Segment alignment constraint   
  115. } Elf32_Phdr;  
  116.   
  117. local uint section_name_off = 0;  
  118. local uint dynsym_name_off = 0;  
  119. local uint oatdata_off = 0;  
  120. local uint oatexec_off = 0;  
  121.   
  122. typedef struct {  
  123.     Elf32_Word off;  
  124.   
  125.     local quad curroff = FTell();  
  126.     FSeek( section_name_off + off );  
  127.     string s_name_str;  
  128.     FSeek( curroff );  
  129. } Elf32_Shdr_Name;  
  130.   
  131. // Section header.   
  132. typedef struct {  
  133.   Elf32_Word sh_name <read=ReadShdrName>;   // Section name (index into string table)   
  134.   Elf32_Word sh_type;     // Section type (SHT_*)   
  135.   Elf32_Word sh_flags;   // Section flags (SHF_*)   
  136.   Elf32_Addr sh_addr;     // Address where section is to be loaded   
  137.   Elf32_Off  sh_offset; // File offset of section data, in bytes   
  138.   Elf32_Word sh_size;     // Size of section, in bytes   
  139.   Elf32_Word sh_link;     // Section type-specific header table index link   
  140.   Elf32_Word sh_info;     // Section type-specific extra information   
  141.   Elf32_Word sh_addralign; // Section address alignment   
  142.   Elf32_Word sh_entsize;   // Size of records contained within the section   
  143. } Elf32_Shdr;  
  144.   
  145. string ReadShdrName(Elf32_Word off) {  
  146.     return ReadString(section_name_off + off);  
  147. }  
  148.   
  149. string ReadDynsymName(Elf32_Word off) {  
  150.     return ReadString(dynsym_name_off + off);  
  151. }  
  152.   
  153. typedef struct {  
  154.     Elf32_Word  st_name;  // Symbol name (index into string table)   
  155.     Elf32_Addr  st_value; // Value or address associated with the symbol   
  156.     Elf32_Word  st_size;  // Size of the symbol   
  157.     unsigned char st_info;  // Symbol's type and binding attributes   
  158.     unsigned char st_other; // Must be zero; reserved   
  159.     Elf32_Half  st_shndx; // Which section (header table index) it's defined in   
  160. } Elf32_Sym_Fixed;  
  161.   
  162. typedef struct {  
  163.     Elf32_Word  st_name <read=ReadDynsymName>;  // Symbol name (index into string table)   
  164.     Elf32_Addr  st_value; // Value or address associated with the symbol   
  165.     Elf32_Word  st_size;  // Size of the symbol   
  166.     unsigned char st_info;  // Symbol's type and binding attributes   
  167.     unsigned char st_other; // Must be zero; reserved   
  168.     Elf32_Half  st_shndx; // Which section (header table index) it's defined in   
  169.   
  170.     if (st_size) {  
  171.         local quad off = FTell();  
  172.         FSeek( st_value );  
  173.         uchar data[st_size];  
  174.         FSeek( off );  
  175.     }  
  176.   
  177.     local string name = ReadDynsymName(st_name);  
  178.     if (Strcmp(name, "oatdata") == 0) {  
  179.         oatdata_off = st_value;  
  180.     }  
  181.   
  182. } Elf32_Sym <optimize=false>;  
  183.   
  184. // local int iter;   
  185. int FindNamedSection( string sect ) {  
  186.     local int i;  
  187.     local string shdr_nn;  
  188.       
  189.     for(i=0; i<file.elf_header.e_shnum; i++ ) {  
  190.         shdr_nn = ReadShdrName(file.elf_section_header[i].sh_name);  
  191.         if( Strcmp( shdr_nn, sect ) == 0 ) {  
  192.             return i;  
  193.         }  
  194.     }  
  195.       
  196.     return -1;  
  197. }  
  198.   
  199. string ReadSection(Elf32_Shdr &shdr) {  
  200.     // Printf("section_name_off=%x", shdr.sh_name);   
  201.     return ReadShdrName(shdr.sh_name);  
  202. }  
  203.   
  204. string ReadDynsymItem(Elf32_Sym &sym) {  
  205.     // Printf("section_name_off=%x", shdr.sh_name);   
  206.     return ReadDynsymName(sym.st_name);  
  207. }  
  208.   
  209. typedef enum {  
  210.   kNone,  
  211.   kArm,  
  212.   kThumb2,  
  213.   kX86,  
  214.   kMips  
  215. } InstructionSet;  
  216.   
  217. /   
  218. //  DexFile format   
  219. /   
  220.   
  221. // struct to read a uleb128 value. uleb128's are a variable-length encoding for   
  222. // a 32 bit value. some of the uleb128/sleb128 code was adapted from dalvik's   
  223. // libdex/Leb128.h   
  224.   
  225. typedef struct {  
  226.     ubyte val <comment="uleb128 element">;  
  227.     if(val > 0x7f) {  
  228.         ubyte val <comment="uleb128 element">;  
  229.         if (val > 0x7f) {  
  230.             ubyte val <comment="uleb128 element">;  
  231.             if(val > 0x7f) {  
  232.                 ubyte val <comment="uleb128 element">;  
  233.                 if(val > 0x7f) {  
  234.                     ubyte val <comment="uleb128 element">;  
  235.                 }  
  236.             }  
  237.         }  
  238.     }  
  239. } uleb128 <read=ULeb128Read, comment="Unsigned little-endian base 128 value">;  
  240.   
  241. // get the actual uint value of the uleb128   
  242. uint uleb128_value(uleb128 &u) {  
  243.     local uint result;  
  244.     local ubyte cur;  
  245.   
  246.     result = u.val[0];  
  247.     if(result > 0x7f) {  
  248.         cur = u.val[1];  
  249.         result = (result & 0x7f) | (uint)((cur & 0x7f) << 7);  
  250.         if(cur > 0x7f) {  
  251.             cur = u.val[2];  
  252.             result |= (uint)(cur & 0x7f) << 14;  
  253.             if(cur > 0x7f) {  
  254.                 cur = u.val[3];  
  255.                 result |= (uint)(cur & 0x7f) << 21;  
  256.                 if(cur > 0x7f) {  
  257.                     cur = u.val[4];  
  258.                     result |= (uint)cur << 28;  
  259.                 }  
  260.             }  
  261.         }  
  262.     }  
  263.   
  264.     return result;  
  265. }  
  266.   
  267. string ULeb128Read(uleb128 &u) {  
  268.     local string s;  
  269.     s = SPrintf(s, "0x%X", uleb128_value(u));  
  270.     return s;  
  271. }  
  272.   
  273. typedef struct {  
  274.     char magic_[8];  
  275.     uint32 checksum_;  // See also location_checksum_   
  276.     uchar signature_[20];  
  277.     uint32 file_size;  // size of entire file   
  278.     uint32 header_size;  // offset to start of next section   
  279.     uint32 endian_tag;  
  280.     uint32 link_size;  // unused   
  281.     uint32 link_off;  // unused   
  282.     uint32 map_off;  // unused   
  283.     uint32 string_ids_size;  // number of StringIds   
  284.     uint32 string_ids_off;  // file offset of StringIds array   
  285.     uint32 type_ids_size;  // number of TypeIds, we don't support more than 65535   
  286.     uint32 type_ids_off;  // file offset of TypeIds array   
  287.     uint32 proto_ids_size;  // number of ProtoIds, we don't support more than 65535   
  288.     uint32 proto_ids_off;  // file offset of ProtoIds array   
  289.     uint32 field_ids_size;  // number of FieldIds   
  290.     uint32 field_ids_off;  // file offset of FieldIds array   
  291.     uint32 method_ids_size;  // number of MethodIds   
  292.     uint32 method_ids_off;  // file offset of MethodIds array   
  293.     uint32 class_defs_size;  // number of ClassDefs   
  294.     uint32 class_defs_off;  // file offset of ClassDef array   
  295.     uint32 data_size;  // unused   
  296.     uint32 data_off;  // unused   
  297. } DexFileHeader;  
  298.   
  299. local int odexpad = 0;  
  300.   
  301. //   
  302. // String IDs   
  303. //   
  304.   
  305. typedef struct {  
  306.     uleb128 utf16_size <comment="Size of string in UTF-16 code units">;  
  307.     string data <comment="A string in MUTF-8 format">;  
  308. } DexFileStringItem;  
  309.   
  310. typedef struct {  
  311.     uint string_data_off <comment="File offset of string data">;  
  312.       
  313.     local int64 pos = FTell();  
  314.     FSeek(odexpad + string_data_off);  
  315.   
  316.     DexFileStringItem string_data <comment="String item">;  
  317.       
  318.     FSeek(pos);  
  319. } DexFileStringId <read=StringDataReader, optimize=false>;  
  320.   
  321. string StringDataReader(DexFileStringId &i) {  
  322.     return i.string_data.data;  
  323. }  
  324.   
  325. typedef struct (int size) {  
  326.     local int s = size;  
  327.     DexFileStringId string_ids[size] <comment="String ID">;  
  328. } DexFileStringIds <read=StringIDListRead, comment="String ID list">;  
  329.   
  330. string StringIDListRead(DexFileStringIds &l) {  
  331.     string s;  
  332.     s = SPrintf(s, "%d strings", l.s);  
  333.     return s;  
  334. }  
  335.   
  336. //   
  337. // type IDs   
  338. //   
  339.   
  340. // read a value from the string table   
  341. string StringIdRead(int id) {  
  342.     if(id == NO_INDEX) {  
  343.         return "NO_INDEX";  
  344.     }  
  345.       
  346.     local string s;  
  347.     SPrintf(s, "(0x%.X) \"%s\"", id, GetStringById(id));  
  348.     return s;  
  349. }  
  350.   
  351. // read a string from the string table   
  352. string GetStringById(int id) {  
  353.     if(id == NO_INDEX) {  
  354.         return "NO_INDEX";  
  355.     }  
  356.   
  357.     if(exists(dex_string_ids.string_id[id])) {  
  358.         return dex_string_ids.string_id[id].string_data.data;  
  359.     } else {  
  360.         return "*** NO STRING";  
  361.     }  
  362. }  
  363.   
  364. string GetTypeById(struct DexFile& dexfile, int id) {  
  365.    if(id == NO_INDEX) {  
  366.         return "NO_INDEX";  
  367.     }  
  368.   
  369.     if(exists(dex_type_ids.type_id[id])) {  
  370.         return GetStringById2(dexfile, dexfile.dex_type_ids.type_id[id].descriptor_idx);  
  371.     } else {  
  372.         return "*** NO TYPE";  
  373.     }  
  374. }  
  375.   
  376. string GetLongTypeDescriptor(string descriptor) {  
  377.     local string desc = "";  
  378.     local string post = "";  
  379.     local int i = 0;  
  380.     local int len = Strlen(descriptor);  
  381.   
  382.     // array descriptors   
  383.     while(descriptor[i] == '[') {  
  384.         post += "[]";  
  385.         i++;  
  386.   
  387.         if(i >= len) return "ERROR";  
  388.     }  
  389.   
  390.     if(descriptor[i] == 'L') {  
  391.         // fully qualified class descriptors   
  392.         i++;  
  393.         while(i < len) {  
  394.             if(descriptor[i] == '/') desc += ".";  
  395.             else if(descriptor[i] == ';'break;  
  396.             else desc += descriptor[i];  
  397.             i++;  
  398.         }  
  399.     } else {  
  400.         // simple type descriptors   
  401.         switch(descriptor[i]) {  
  402.             case 'V': desc = "void"break;  
  403.             case 'Z': desc = "boolean"break;  
  404.             case 'B': desc = "byte"break;  
  405.             case 'S': desc = "short"break;  
  406.             case 'C': desc = "char"break;  
  407.             case 'I': desc = "int"break;  
  408.             case 'J': desc = "long"break;  
  409.             case 'F': desc = "float"break;  
  410.             case 'D': desc = "double"break;  
  411.         }  
  412.     }  
  413.   
  414.     return desc + post;  
  415. }  
  416.   
  417. string GetLongTypeById(int id) {  
  418.     return GetLongTypeDescriptor(GetTypeById(id));  
  419. }  
  420.   
  421. string GetMethodById(int id) {  
  422.     if(id == NO_INDEX) {  
  423.         return "NO_INDEX";  
  424.     }  
  425.   
  426.     if(exists(dex_method_ids.method_id[id])) {  
  427.         return MethodIdItemRead(dex_method_ids.method_id[id]);  
  428.     } else {  
  429.         return "*** NO METHOD";  
  430.     }  
  431. }  
  432.   
  433. string GetFieldById(int id) {  
  434.     if(id == NO_INDEX) {  
  435.         return "NO_INDEX";  
  436.     }  
  437.   
  438.     if(exists(dex_field_ids.field_id[id])) {  
  439.         return FieldIdItemRead(dex_field_ids.field_id[id]);  
  440.     } else {  
  441.         return "*** NO FIELD";  
  442.     }  
  443. }  
  444.   
  445. typedef struct {  
  446.     uint descriptor_idx <comment="String ID for this type descriptor">;  
  447.     local string name = GetStringById2(parentof(parentof(this)), descriptor_idx);  
  448. } DexFileTypeId <read=TypeIDRead, optimize=false>;  
  449.   
  450. string GetStringById2(struct DexFile& dexfile, int id) {  
  451.      if(id == NO_INDEX) {  
  452.         return "NO_INDEX";  
  453.     }  
  454.   
  455.     if(exists(dexfile.dex_string_ids.string_ids[id])) {  
  456.         return dexfile.dex_string_ids.string_ids[id].string_data.data;  
  457.     } else {  
  458.         return "*** NO STRING";  
  459.     }  
  460. }  
  461.   
  462. string TypeIDRead(DexFileTypeId &i) {  
  463.     return i.name;  
  464. }  
  465.   
  466. typedef struct (int size) {  
  467.     local int s = size;  
  468.     DexFileTypeId type_id[size] <comment="Type ID">;  
  469. } DexFileTypeIds <read=TypeIDListRead>;  
  470.   
  471. string TypeIDListRead(DexFileTypeIds &l) {  
  472.     string s;  
  473.     s = SPrintf(s, "%d types", l.s);  
  474.     return s;  
  475. }  
  476.   
  477. // proto    
  478.   
  479. typedef struct {  
  480.     ushort type_idx <comment="Index into type_ids list">;  
  481.     local string type = GetLongTypeDescriptor(GetTypeById(parentof(parentof(parentof(parentof(this)))), return_type_idx));  
  482. } DexFileTypeItem <optimize=false>;  
  483.   
  484. typedef struct {  
  485.     uint size <comment="Number of entries in type list">;  
  486.     DexFileTypeItem list[size] <read=TypeItemRead, comment="Type entry">;  
  487. } DexFileTypeList <read=TypeItemListRead, optimize=false>;  
  488.   
  489. string TypeItemRead(DexFileTypeItem &t) {  
  490.     return t.type;  
  491. }  
  492.   
  493. string TypeItemListRead(DexFileTypeList &l) {  
  494.     string s = "";  
  495.     string tmp;  
  496.     int i;  
  497.   
  498.     for(i = 0; i < l.size; i++) {  
  499.         s += l.list[i].type;  
  500.         if(i+1 < l.size) {  
  501.             s += ", ";  
  502.         }  
  503.     }  
  504.     return s;  
  505. }  
  506.   
  507. typedef struct {  
  508.     uint shorty_idx <comment="String ID of short-form descriptor">;  
  509.     local string shorty = GetStringById2(parentof(parentof(this)), shorty_idx);  
  510.       
  511.     uint return_type_idx <comment="Type ID of the return type">;  
  512.     local string return_type = GetLongTypeDescriptor(GetTypeById(parentof(parentof(this)), return_type_idx));  
  513.       
  514.     uint parameters_off <comment="File offset of parameter type list">;  
  515.   
  516.     if(parameters_off != 0) {  
  517.         local int64 pos = FTell();  
  518.         FSeek(odexpad + parameters_off);  
  519.   
  520.         DexFileTypeList parameters <comment="Prototype parameter data">;  
  521.       
  522.         FSeek(pos);  
  523.     }  
  524.   
  525. } DexFileProtoId <read=ProtoIDItemRead, optimize=false>;  
  526.   
  527. string ProtoIDItemRead(DexFileProtoId &i) {  
  528.     return GetPrototypeSignature(i);  
  529. }  
  530.   
  531. string GetParameterListString(DexFileTypeList &l) {  
  532.     local string s = "(";  
  533.     local string tmp;  
  534.     local int i;  
  535.   
  536.     for(i = 0; i < l.size; i++) {  
  537.         s += l.list[i].type;  
  538.         if(i+1 < l.size) {  
  539.             s += ", ";  
  540.         }  
  541.     }  
  542.     return s + ")";  
  543. }  
  544.   
  545. string GetPrototypeSignature(DexFileProtoId &item) {  
  546.     string ret = item.return_type;  
  547.     string params = "()";  
  548.     if(exists(item.parameters)) {  
  549.         params = GetParameterListString(item.parameters);  
  550.     }   
  551.   
  552.     return ret + " " + params;  
  553. }  
  554.   
  555. typedef struct (int size) {  
  556.     local int s = size;  
  557.     DexFileProtoId proto_id[size] <comment="Prototype ID">;  
  558. } DexFileProtoIds <read=ProtoIDListRead>;  
  559.   
  560. string ProtoIDListRead(DexFileProtoIds &l) {  
  561.     string s;  
  562.     s = SPrintf(s, "%d protot ypes", l.s);  
  563.     return s;  
  564. }  
  565.   
  566.   
  567. //   
  568. // fields   
  569. //   
  570.   
  571. typedef struct {  
  572.     ushort class_idx <comment="Type ID of the class that defines this field">;  
  573.     local string class = GetLongTypeDescriptor(GetTypeById(parentof(parentof(this)), class_idx));  
  574.       
  575.     ushort type_idx <comment="Type ID for the type of this field">;  
  576.     local string type = GetLongTypeDescriptor(GetTypeById(parentof(parentof(this)), type_idx));  
  577.       
  578.     uint name_idx <comment="String ID for the field's name">;  
  579.     local string name = GetStringById2(parentof(parentof(this)), name_idx);  
  580.       
  581. } DexFileFieldId <read=FieldIdItemRead, optimize=false>;  
  582.   
  583. string FieldIdItemRead(DexFileFieldId &i) {  
  584.     return  i.type + " " + i.class + " : " + i.name;  
  585. }  
  586.   
  587. typedef struct (int size) {  
  588.     local int s = size;  
  589.     DexFileFieldId field_id[size] <comment="Field ID">;  
  590. } DexFileFieldIds <read=FieldIDListRead>;  
  591.   
  592. string FieldIDListRead(DexFileFieldIds &l) {  
  593.     string s;  
  594.     s = SPrintf(s, "%d fields", l.s);  
  595.     return s;  
  596. }  
  597.   
  598. //   
  599. // methods   
  600. //   
  601.   
  602. typedef struct {  
  603.     ushort class_idx <comment="Type ID of the class that defines this method">;  
  604.     local string class = GetLongTypeDescriptor(GetTypeById(parentof(parentof(this)), class_idx));  
  605.       
  606.     ushort proto_idx <comment="Prototype ID for this method">;  
  607.     local string proto = "";  
  608.       
  609.     uint name_idx <comment="String ID for the method's name">;  
  610.     local string name = GetStringById2(parentof(parentof(this)), name_idx);  
  611. } DexFileMethodId <read=MethodIdItemRead, optimize=false>;  
  612.   
  613. string ProtoIdxRead(ushort p) {  
  614.     string s;  
  615.     SPrintf(s, "(0x%X) %s", p, GetPrototypeSignature(dex_proto_ids.proto_id[p]));  
  616.     return s;  
  617. }  
  618.   
  619. string MethodIdItemRead(DexFileMethodId &m) {  
  620. //  local string retval = GetLongTypeDescriptor(GetTypeById(dex_proto_ids.proto_id[m.proto_idx].return_type_idx));   
  621. //  local string classname = GetLongTypeDescriptor(GetStringById(dex_type_ids.type_id[m.class_idx].descriptor_idx));   
  622. //  local string methodname = GetStringById(m.name_idx);   
  623. //  local string params = "()";   
  624. //  if(exists(dex_proto_ids.proto_id[m.proto_idx].parameters)) {   
  625. //      params = GetParameterListString(dex_proto_ids.proto_id[m.proto_idx].parameters);   
  626. //  }    
  627.     return m.proto + " " + m.class + "." + m.name;  
  628. }  
  629.   
  630. typedef struct (int size) {  
  631.     local int s = size;  
  632.     DexFileMethodId method_id[size] <comment="Method ID">;  
  633. } DexFileMethodIds <read=MethodIDListRead>;  
  634.   
  635. string MethodIDListRead(DexFileMethodIds &l) {  
  636.     string s;  
  637.     s = SPrintf(s, "%d methods", l.s);  
  638.     return s;  
  639. }  
  640.   
  641.   
  642.   
  643. // access flags. some of these mean different things for different items (class/field/method)   
  644. typedef enum <uint> {  
  645.     ACC_PUBLIC = 0x1,  
  646.     ACC_PRIVATE = 0x2,  
  647.     ACC_PROTECTED = 0x4,  
  648.     ACC_STATIC = 0x8,  
  649.     ACC_FINAL = 0x10,  
  650.     ACC_SYNCHRONIZED = 0x20,  
  651.     ACC_VOLATILE = 0x40, // field   
  652.     //ACC_BRIDGE = 0x40, // method   
  653.     ACC_TRANSIENT = 0x80, // field   
  654.     //ACC_VARARGS = 0x80, // method   
  655.     ACC_NATIVE = 0x100,  
  656.     ACC_INTERFACE = 0x200,  
  657.     ACC_ABSTRACT = 0x400,  
  658.     ACC_STRICT = 0x800,  
  659.     ACC_SYNTHETIC = 0x1000,  
  660.     ACC_ANNOTATION = 0x2000,  
  661.     ACC_ENUM = 0x4000,  
  662.     ACC_CONSTRUCTOR = 0x10000,  
  663.     ACC_DECLARED_SYNCHRONIZED = 0x20000  
  664. } ACCESS_FLAGS <read=AccessFlagsRead>;  
  665.   
  666. string AccessFlagsRead(ACCESS_FLAGS f) {  
  667.     string ret = "";  
  668.     string flags = "";  
  669.     ACCESS_FLAGS i = 1;  
  670.   
  671.     while(i <= ACC_DECLARED_SYNCHRONIZED) {  
  672.         if (f & i) {  
  673.             flags += EnumToString(i) + " ";  
  674.         }  
  675.         i = i << 1;  
  676.     }  
  677.   
  678.     SPrintf(ret, "(0x%X) %s", f, flags);  
  679.     return ret;  
  680. }  
  681.   
  682.   
  683. typedef enum {  
  684.     AF_CLASS, AF_FIELD, AF_METHOD  
  685. } AF_TYPE;  
  686.   
  687. string GetFriendlyAccessFlag(int flag, AF_TYPE type) {  
  688.     switch (flag) {  
  689.         case ACC_PUBLIC: return "public";  
  690.         case ACC_PRIVATE: return "private";  
  691.         case ACC_PROTECTED: return "protected";  
  692.         case ACC_STATIC: return "static";  
  693.         case ACC_FINAL: return "final";  
  694.         case ACC_SYNCHRONIZED: return "synchronized";  
  695.         case ACC_VOLATILE:  
  696.             if(type == AF_FIELD) return "volatile";  
  697.             else return "bridge"// 0x40 is 'bridge' for methods   
  698.         case ACC_TRANSIENT:  
  699.             if(type == AF_FIELD) return "transient";  
  700.             else return "varargs"// 0x80 is 'varargs' for methods   
  701.         case ACC_NATIVE: return "native";  
  702.         case ACC_INTERFACE: return "interface";  
  703.         case ACC_ABSTRACT: return "abstract";  
  704.         case ACC_STRICT: return "strict";  
  705.         case ACC_SYNTHETIC: return "synthetic";  
  706.         case ACC_ANNOTATION: return "annotation";  
  707.         case ACC_ENUM: return "enum";  
  708.         case ACC_CONSTRUCTOR: return "constructor";  
  709.         case ACC_DECLARED_SYNCHRONIZED: return "declared-synchronized";  
  710.     }  
  711.     return "ERROR";  
  712. }  
  713.   
  714. string GetFriendlyAccessFlags(ACCESS_FLAGS f, AF_TYPE type) {  
  715.     string flags = "";  
  716.     ACCESS_FLAGS i = 1;  
  717.   
  718.     while(i <= ACC_DECLARED_SYNCHRONIZED) {  
  719.         if (f & i) {  
  720.             flags += GetFriendlyAccessFlag(i, type) + " ";  
  721.         }  
  722.         i = i << 1;  
  723.     }  
  724.   
  725.     return flags;  
  726. }  
  727.   
  728. typedef struct {  
  729.     uleb128 static_fields_size <comment="The number of static fields">;  
  730.     uleb128 instance_fields_size <comment="The number of instance fields">;  
  731.     uleb128 direct_methods_size <comment="The number of direct methods">;  
  732.     uleb128 virtual_methods_size <comment="The number of virtual methods">;  
  733.   
  734.     if(uleb128_value(static_fields_size) > 0) {  
  735. //      encoded_field_list static_fields(uleb128_value(static_fields_size)) <comment="Encoded sequence of static fields">;   
  736.     }  
  737.   
  738.     if(uleb128_value(instance_fields_size) > 0) {  
  739. //      encoded_field_list instance_fields(uleb128_value(instance_fields_size)) <comment="Encoded sequence of instance fields">;   
  740.     }  
  741.   
  742.     if(uleb128_value(direct_methods_size) > 0) {  
  743. //      encoded_method_list direct_methods(uleb128_value(direct_methods_size)) <comment="Encoded sequence of direct methods">;   
  744.     }  
  745.   
  746.     if(uleb128_value(virtual_methods_size) > 0) {  
  747. //      encoded_method_list virtual_methods(uleb128_value(virtual_methods_size)) <comment="Encoded sequence of virtual methods">;   
  748.     }  
  749. } DexFileClassData <read=ClassDataItemRead>;  
  750.   
  751. string ClassDataItemRead(DexFileClassData &i) {  
  752.     local string s;  
  753.     SPrintf(s, "%i static fields, %i instance fields, %i direct methods, %i virtual methods",  
  754.         uleb128_value(i.static_fields_size), uleb128_value(i.instance_fields_size),   
  755.         uleb128_value(i.direct_methods_size), uleb128_value(i.virtual_methods_size));  
  756.     return s;  
  757. }  
  758.   
  759. typedef struct {  
  760.     local int64 pos;  
  761.   
  762.     uint class_idx <comment="Type ID for this class">;  
  763.     local string class = GetLongTypeDescriptor(GetTypeById(parentof(parentof(this)), class_idx));  
  764.       
  765.     ACCESS_FLAGS access_flags <comment="Access flags">;  
  766.     uint superclass_idx <read=LongTypeIdRead, comment="Type ID for this class's superclass">;  
  767.     local string superclass = GetLongTypeDescriptor(GetTypeById(parentof(parentof(this)), superclass_idx));  
  768.   
  769.     uint interfaces_off <comment="File offset to interface list">;  
  770.     if(interfaces_off != 0) {  
  771.         pos = FTell();  
  772.         FSeek(odexpad + interfaces_off);  
  773.         // type_item_list interfaces <read=InterfacesRead, comment="Interface data">;   
  774.         FSeek(pos);  
  775.     }  
  776.   
  777.     uint source_file_idx <comment="String ID for the name of the file with this class defined">;  
  778.     local string source_path = GetStringById2(parentof(parentof(this)), source_file_idx);  
  779.   
  780.     uint annotations_off <comment="File offset to the annotation structure for this class">;  
  781.     if(annotations_off != 0) {  
  782.         pos = FTell();  
  783.         FSeek(odexpad + annotations_off);  
  784.         // annotations_directory_item annotations <comment="Annotation data">;   
  785.         FSeek(pos);  
  786.     }  
  787.   
  788.     uint class_data_off <comment="File offset to the class data for this class">;  
  789.     if(class_data_off != 0) {  
  790.         pos = FTell();  
  791.         FSeek(odexpad + class_data_off);  
  792.         DexFileClassData class_data <comment="Class data">;  
  793.         FSeek(pos);  
  794.     }  
  795.   
  796.     uint static_values_off <comment="File offset to static field data">;  
  797.     if(static_values_off != 0) {  
  798.         pos = FTell();  
  799.         FSeek(odexpad + static_values_off);  
  800.         // struct encoded_array_item static_values <comment="Static values">;   
  801.         FSeek(pos);       
  802.     }  
  803. } DexFileClassDefItem <read=ClassDefItemRead, optimize=false>;  
  804.   
  805. string ClassDefItemRead(DexFileClassDefItem &i) {  
  806.     local string flags = GetFriendlyAccessFlags(i.access_flags, AF_CLASS);  
  807.     return flags + i.class;  
  808. }  
  809.   
  810. typedef struct (int size) {  
  811.     local int s = size;  
  812.     DexFileClassDefItem class_def[size] <comment="Class ID">;  
  813. } DexFileClassDefs <read=ClassDefItemListRead>;  
  814.   
  815. string ClassDefItemListRead(DexFileClassDefs &l) {  
  816.     string s;  
  817.     s = SPrintf(s, "%d classes", l.s);  
  818.     return s;  
  819. }  
  820.   
  821. //   
  822. // map list   
  823. //   
  824.   
  825. enum <ushort> TYPE_CODES {  
  826.     TYPE_HEADER_ITEM = 0x0000,  
  827.     TYPE_STRING_ID_ITEM = 0x0001,  
  828.     TYPE_TYPE_ID_ITEM = 0x0002,  
  829.     TYPE_PROTO_ID_ITEM = 0x0003,  
  830.     TYPE_FIELD_ID_ITEM = 0x0004,  
  831.     TYPE_METHOD_ID_ITEM = 0x0005,  
  832.     TYPE_CLASS_DEF_ITEM = 0x0006,  
  833.   
  834.     TYPE_MAP_LIST = 0x1000,  
  835.     TYPE_TYPE_LIST = 0x1001,  
  836.     TYPE_ANNOTATION_SET_REF_LIST = 0x1002,  
  837.     TYPE_ANNOTATION_SET_ITEM = 0x1003,  
  838.   
  839.     TYPE_CLASS_DATA_ITEM = 0x2000,  
  840.     TYPE_CODE_ITEM = 0x2001,  
  841.     TYPE_STRING_DATA_ITEM = 0x2002,  
  842.     TYPE_DEBUG_INFO_ITEM = 0x2003,  
  843.     TYPE_ANNOTATION_ITEM = 0x2004,  
  844.     TYPE_ENCODED_ARRAY_ITEM = 0x2005,  
  845.     TYPE_ANNOTATIONS_DIRECTORY_ITEM = 0x2006  
  846. };  
  847.   
  848. typedef struct {  
  849.     TYPE_CODES type;  
  850.     ushort unused;  
  851.     uint size;  
  852.     uint offset;    
  853. } DexFileMapItem <read=MapItemRead>;  
  854.   
  855. string MapItemRead(DexFileMapItem &m) {  
  856.     string s;  
  857.     SPrintf(s, "%s", EnumToString(m.type));  
  858.     return s;  
  859. }  
  860.   
  861. typedef struct {  
  862.     uint size;  
  863.     DexFileMapItem list[size];  
  864. } DexFileMapList <read=MapListTypeRead>;  
  865.   
  866. string MapListTypeRead(DexFileMapList &t) {  
  867.     local string s;  
  868.     SPrintf(s, "%i items", t.size);  
  869.     return s;  
  870. }  
  871.   
  872. //   
  873. // dex file   
  874. //   
  875.   
  876. typedef struct {  
  877.     DexFileHeader header;  
  878.       
  879.     if(header.map_off != 0) {  
  880.         FSeek(odexpad + header.map_off);  
  881.         DexFileMapList dex_map_list <comment="Map list">;  
  882.           
  883.         local int i;  
  884.         for (i=0; i<dex_map_list.size; i++) {  
  885.             FSeek(oatdata_off + dex_file_offset + dex_map_list.list[i].offset);  
  886.             if (dex_map_list.list[i].type == TYPE_STRING_ID_ITEM) {  
  887.                 DexFileStringIds dex_string_ids(header.string_ids_size) <comment="String ID list">;  
  888.             } else if (dex_map_list.list[i].type == TYPE_TYPE_ID_ITEM) {  
  889.                 DexFileTypeIds dex_type_ids(header.type_ids_size) <comment="Type ID list">;  
  890.             } else if (dex_map_list.list[i].type == TYPE_PROTO_ID_ITEM) {  
  891.                 DexFileProtoIds dex_proto_ids(header.proto_ids_size) <comment="Proto ID list">;  
  892.             } else if (dex_map_list.list[i].type == TYPE_FIELD_ID_ITEM) {  
  893.                 DexFileFieldIds dex_field_ids(header.field_ids_size) <comment="Field ID list">;  
  894.             } else if (dex_map_list.list[i].type == TYPE_METHOD_ID_ITEM) {  
  895.                 DexFileMethodIds dex_method_ids(header.method_ids_size) <comment="Method ID list">;  
  896.             } else if (dex_map_list.list[i].type == TYPE_CLASS_DEF_ITEM) {  
  897.                 DexFileClassDefs dex_class_defs(header.class_defs_size) <comment="Class Defs">;  
  898.             } else {  
  899.                 // uint UNPROCESS_TYPE = dex_map_list.list[i].type;   
  900.             }  
  901.         }  
  902.     }  
  903. } DexFile;  
  904.   
  905. typedef struct {  
  906.     uint32 code_offset_;  
  907.     uint32 frame_size_in_bytes_;  
  908.     uint32 core_spill_mask_;  
  909.     uint32 fp_spill_mask_;  
  910.     uint32 mapping_table_offset_;  
  911.     uint32 vmap_table_offset_;  
  912.     uint32 gc_map_offset_;  
  913.       
  914.     local uint32 off = code_offset_ & ~0x1;  
  915.     if (off > 0) {  
  916.         Printf("code_offset [%x][%x] = %x\n", code_offset_, off, off + 0x1000);  
  917.     }  
  918. } OatMethodOffsets;  
  919.   
  920. typedef struct (int index) {  
  921.     uint32 status;  
  922.     local int methodCount = getClassMethodCount(parentof(parentof(this)), index);  
  923.     local string name = getClassName(parentof(parentof(this)), index);  
  924.       
  925.     if (methodCount > 0) {  
  926.         OatMethodOffsets methodOffset[methodCount] <optimize=false>;  
  927.     }  
  928. } OatClass <read=ReadOatClass, optimize=false>;  
  929.   
  930. string ReadOatClass(OatClass &c) {  
  931.     return c.name;  
  932. }  
  933.   
  934. typedef struct (int size) {  
  935.     local int total = size;  
  936.     local int idx;  
  937.     for (idx=0; idx<size; idx++) {  
  938.         OatClass oat_class(idx);  
  939.     }  
  940. } OatClasses <read=ReadOatClasses>;  
  941.   
  942. string ReadOatClasses(OatClasses &oc) {  
  943.     local string s;  
  944.     SPrintf(s, "%i classes", oc.total);  
  945.     return s;  
  946. }  
  947.   
  948. string getClassName(struct OatDexFile& oatfile, int classIdx) {  
  949.     if (exists(oatfile.dex_file.dex_class_defs.class_def[classIdx])) {  
  950.         return oatfile.dex_file.dex_class_defs.class_def[classIdx].class;  
  951.     }  
  952.     return "** NO NAME **";  
  953. }  
  954.   
  955. int getClassMethodCount(struct OatDexFile& oatfile, int classIdx) {  
  956.     if (exists(oatfile.dex_file.dex_class_defs.class_def[classIdx])) {  
  957.         if (exists(oatfile.dex_file.dex_class_defs.class_def[classIdx].class_data)) {  
  958.             local int dirNum = uleb128_value(oatfile.dex_file.dex_class_defs.class_def[classIdx].class_data.direct_methods_size);  
  959.             local int virNum = uleb128_value(oatfile.dex_file.dex_class_defs.class_def[classIdx].class_data.virtual_methods_size);  
  960.             return dirNum + virNum;  
  961.         }  
  962.     }  
  963.     return 0;  
  964. }  
  965.   
  966. typedef struct {  
  967.     uint32 dex_file_location_size;  
  968.     char   dex_file_location_data[dex_file_location_size];  
  969.     uint32 dex_file_checksum;  
  970.     uint32 dex_file_offset;  
  971.       
  972.     local quad off = FTell();  
  973.     local quad method_count = (oatdata_off + dex_file_offset - off) / sizeof(uint32);  
  974.     uint32 method_offs[method_count];  
  975.   
  976.     odexpad = oatdata_off + dex_file_offset;  
  977.     FSeek(oatdata_off + dex_file_offset);  
  978.     DexFile dex_file;  
  979.       
  980.     FSeek(oatdata_off + dex_file_offset + dex_file.header.file_size);  
  981.     OatClasses oat_classes(dex_file.header.class_defs_size) ;  
  982.       
  983. } OatDexFile <optimize=false>;  
  984.   
  985. typedef struct {  
  986.     char      magic[4];  
  987.     char      version[4];  
  988.     uint32  checksum;  
  989.     InstructionSet instruction_set;  
  990.   
  991.     uint32 dex_file_count;  
  992.     uint32 executable_offset_;  
  993.     uint32 interpreter_to_interpreter_bridge_offset_;  
  994.     uint32 interpreter_to_compiled_code_bridge_offset_;  
  995.     uint32 jni_dlsym_lookup_offset_;  
  996.     uint32 portable_resolution_trampoline_offset_;  
  997.     uint32 portable_to_interpreter_bridge_offset_;  
  998.     uint32 quick_resolution_trampoline_offset_;  
  999.     uint32 quick_to_interpreter_bridge_offset_;  
  1000.   
  1001.     uint32 image_file_location_oat_checksum_;  
  1002.     uint32 image_file_location_oat_data_begin_;  
  1003.     uint32 image_file_location_size;  
  1004.     char   image_file_location_data[image_file_location_size];  
  1005. } OatHeader;  
  1006.   
  1007. struct {  
  1008.     Elf32_Ehdr elf_header;  
  1009.     if (elf_header.e_phnum > 0) {  
  1010.         FSeek(elf_header.e_phoff);  
  1011.         Elf32_Phdr elf_program_header[elf_header.e_phnum];  
  1012.     }  
  1013.       
  1014.     local uint soff = elf_header.e_shoff + elf_header.e_shentsize * elf_header.e_shstrndx;  
  1015.     section_name_off = ReadUInt(soff + 3 * sizeof( Elf32_Word ) + sizeof( Elf32_Addr ));  
  1016.     // Printf("section_name_off=%x", section_name_off);   
  1017.   
  1018.     if (elf_header.e_shnum > 0) {  
  1019.         FSeek(elf_header.e_shoff);  
  1020.         Elf32_Shdr elf_section_header[elf_header.e_shnum] <read=ReadSection>;  
  1021.   
  1022.         local uint strindex = FindNamedSection(".dynstr");  
  1023.         dynsym_name_off = elf_section_header[strindex].sh_offset;  
  1024.   
  1025.         local uint symindex = FindNamedSection(".dynsym");  
  1026.         local uint symcount = elf_section_header[symindex].sh_size / sizeof(Elf32_Sym_Fixed);  
  1027.         FSeek(elf_section_header[symindex].sh_offset);  
  1028.       
  1029.         // dynsym   
  1030.         Elf32_Sym symtab[symcount] <read=ReadDynsymItem>;  
  1031.           
  1032.         // dynstr   
  1033.         if (elf_section_header[strindex].sh_size > 0) {  
  1034.             local quad off = FTell();  
  1035.             FSeek( dynsym_name_off );  
  1036.             char dynstr[elf_section_header[strindex].sh_size];  
  1037.             FSeek( off );  
  1038.         }  
  1039.           
  1040.         // hash   
  1041.         local uint hashindex = FindNamedSection(".hash");  
  1042.         FSeek( elf_section_header[hashindex].sh_offset );  
  1043.         Elf32_Word hash[elf_section_header[hashindex].sh_size];  
  1044.           
  1045.         // rodata   
  1046.         local uint rodataindex = FindNamedSection(".rodata");  
  1047.         FSeek( elf_section_header[rodataindex].sh_offset );  
  1048.         uchar rodata[elf_section_header[rodataindex].sh_size];  
  1049.           
  1050.         // text   
  1051.         local uint textindex = FindNamedSection(".text");  
  1052.         FSeek( elf_section_header[textindex].sh_offset );  
  1053.         uchar text[elf_section_header[textindex].sh_size];  
  1054.           
  1055.         // dynamic   
  1056.         local uint dynamicindex = FindNamedSection(".dynamic");  
  1057.         FSeek( elf_section_header[dynamicindex].sh_offset );  
  1058.         uchar dynamic[elf_section_header[dynamicindex].sh_size];  
  1059.           
  1060.         // shstrtab   
  1061.         local uint shstrtabindex = FindNamedSection(".shstrtab");  
  1062.         FSeek( elf_section_header[shstrtabindex].sh_offset );  
  1063.         char shstrtab[elf_section_header[shstrtabindex].sh_size];  
  1064.     }  
  1065.   
  1066.     if (oatdata_off > 0) {  
  1067.         FSeek(oatdata_off);  
  1068.   
  1069.         OatHeader oat_header;  
  1070.         OatDexFile dex_files[oat_header.dex_file_count];  
  1071.     }  
  1072. } file;  
//-----------------------------------//--- 010 Editor v2.0 Binary Template//// File:     OATTemplate.bt// Author:   tomken// Revision: 1.0// Purpose:  Defines a template for//    parsing OAT files.//-----------------------------------LittleEndian();#define NO_INDEX (0xFFFFFFFF)typedef uint32 Elf32_Addr; // Program addresstypedef uint32 Elf32_Off;  // File offsettypedef uint16 Elf32_Half;typedef uint32 Elf32_Word;typedef int	Elf32_Sword;// Object file magic string.// static const char ElfMagic[] = { 0x7f, 'E', 'L', 'F', '\0' };// e_ident size and indices.typedef enum 
{ EI_MAG0 = 0, // File identification index. EI_MAG1 = 1, // File identification index. EI_MAG2 = 2, // File identification index. EI_MAG3 = 3, // File identification index. EI_CLASS = 4, // File class. EI_DATA = 5, // Data encoding. EI_VERSION = 6, // File version. EI_OSABI = 7, // OS/ABI identification. EI_ABIVERSION = 8, // ABI version. EI_PAD = 9, // Start of padding bytes. EI_NIDENT = 16 // Number of bytes in e_ident.} EI_Type;typedef struct { unsigned char e_ident[EI_NIDENT]; // ELF Identification bytes Elf32_Half e_type; // Type of file (see ET_* below) Elf32_Half e_machine; // Required architecture for this file (see EM_*) Elf32_Word e_version; // Must be equal to 1 Elf32_Addr e_entry; // Address to jump to in order to start program Elf32_Off e_phoff; // Program header table's file offset, in bytes Elf32_Off e_shoff; // Section header table's file offset, in bytes Elf32_Word e_flags; // Processor-specific flags Elf32_Half e_ehsize; // Size of ELF header, in bytes Elf32_Half e_phentsize; // Size of an entry in the program header table Elf32_Half e_phnum; // Number of entries in the program header table Elf32_Half e_shentsize; // Size of an entry in the section header table Elf32_Half e_shnum; // Number of entries in the section header table Elf32_Half e_shstrndx; // Sect hdr table index of sect name string table} Elf32_Ehdr;// Segment types.enum { PT_NULL = 0, // Unused segment. PT_LOAD = 1, // Loadable segment. PT_DYNAMIC = 2, // Dynamic linking information. PT_INTERP = 3, // Interpreter pathname. PT_NOTE = 4, // Auxiliary information. PT_SHLIB = 5, // Reserved. PT_PHDR = 6, // The program header table itself. PT_TLS = 7, // The thread-local storage template. PT_LOOS = 0x60000000, // Lowest operating system-specific pt entry type. PT_HIOS = 0x6fffffff, // Highest operating system-specific pt entry type. PT_LOPROC = 0x70000000, // Lowest processor-specific program hdr entry type. PT_HIPROC = 0x7fffffff, // Highest processor-specific program hdr entry type. // x86-64 program header types. // These all contain stack unwind tables. PT_GNU_EH_FRAME = 0x6474e550, PT_SUNW_EH_FRAME = 0x6474e550, PT_SUNW_UNWIND = 0x6464e550, PT_GNU_STACK = 0x6474e551, // Indicates stack executability. PT_GNU_RELRO = 0x6474e552, // Read-only after relocation. // ARM program header types. PT_ARM_ARCHEXT = 0x70000000, // Platform architecture compatibility info // These all contain stack unwind tables. PT_ARM_EXIDX = 0x70000001, PT_ARM_UNWIND = 0x70000001};string ReadPhdrType(Elf32_Word flag) { switch (flag) { case PT_NULL: return "null"; case PT_LOAD: return "load"; case PT_DYNAMIC: return "dynamic"; case PT_INTERP: return "interp"; case PT_NOTE: return "note"; case PT_SHLIB: return "shlib"; case PT_PHDR: return "phdr"; case PT_TLS: return "tls"; case PT_LOOS: return "loos"; case PT_HIOS: return "hios"; case PT_LOPROC: return "loproc"; case PT_HIPROC: return "hiproc"; } return "ERROR";}// Program header for ELF32.typedef struct { Elf32_Word p_type
; // Type of segment Elf32_Off p_offset; // File offset where segment is located, in bytes Elf32_Addr p_vaddr; // Virtual address of beginning of segment Elf32_Addr p_paddr; // Physical address of beginning of segment (OS-specific) Elf32_Word p_filesz; // Num. of bytes in file image of segment (may be zero) Elf32_Word p_memsz; // Num. of bytes in mem image of segment (may be zero) Elf32_Word p_flags; // Segment flags Elf32_Word p_align; // Segment alignment constraint} Elf32_Phdr;local uint section_name_off = 0;local uint dynsym_name_off = 0;local uint oatdata_off = 0;local uint oatexec_off = 0;typedef struct { Elf32_Word off; local quad curroff = FTell(); FSeek( section_name_off + off ); string s_name_str; FSeek( curroff );} Elf32_Shdr_Name;// Section header.typedef struct { Elf32_Word sh_name
; // Section name (index into string table) Elf32_Word sh_type; // Section type (SHT_*) Elf32_Word sh_flags; // Section flags (SHF_*) Elf32_Addr sh_addr; // Address where section is to be loaded Elf32_Off sh_offset; // File offset of section data, in bytes Elf32_Word sh_size; // Size of section, in bytes Elf32_Word sh_link; // Section type-specific header table index link Elf32_Word sh_info; // Section type-specific extra information Elf32_Word sh_addralign; // Section address alignment Elf32_Word sh_entsize; // Size of records contained within the section} Elf32_Shdr;string ReadShdrName(Elf32_Word off) { return ReadString(section_name_off + off);}string ReadDynsymName(Elf32_Word off) { return ReadString(dynsym_name_off + off);}typedef struct { Elf32_Word st_name; // Symbol name (index into string table) Elf32_Addr st_value; // Value or address associated with the symbol Elf32_Word st_size; // Size of the symbol unsigned char st_info; // Symbol's type and binding attributes unsigned char st_other; // Must be zero; reserved Elf32_Half st_shndx; // Which section (header table index) it's defined in} Elf32_Sym_Fixed;typedef struct { Elf32_Word st_name
; // Symbol name (index into string table) Elf32_Addr st_value; // Value or address associated with the symbol Elf32_Word st_size; // Size of the symbol unsigned char st_info; // Symbol's type and binding attributes unsigned char st_other; // Must be zero; reserved Elf32_Half st_shndx; // Which section (header table index) it's defined in if (st_size) { local quad off = FTell(); FSeek( st_value ); uchar data[st_size]; FSeek( off ); } local string name = ReadDynsymName(st_name); if (Strcmp(name, "oatdata") == 0) { oatdata_off = st_value; }} Elf32_Sym
;// local int iter;int FindNamedSection( string sect ) { local int i; local string shdr_nn; for(i=0; i
; if(val > 0x7f) { ubyte val
; if (val > 0x7f) { ubyte val
; if(val > 0x7f) { ubyte val
; if(val > 0x7f) { ubyte val
; } } } }} uleb128
;// get the actual uint value of the uleb128uint uleb128_value(uleb128 &u) { local uint result; local ubyte cur; result = u.val[0]; if(result > 0x7f) { cur = u.val[1]; result = (result & 0x7f) | (uint)((cur & 0x7f) << 7); if(cur > 0x7f) { cur = u.val[2]; result |= (uint)(cur & 0x7f) << 14; if(cur > 0x7f) { cur = u.val[3]; result |= (uint)(cur & 0x7f) << 21; if(cur > 0x7f) { cur = u.val[4]; result |= (uint)cur << 28; } } } } return result;}string ULeb128Read(uleb128 &u) { local string s; s = SPrintf(s, "0x%X", uleb128_value(u)); return s;}typedef struct { char magic_[8]; uint32 checksum_; // See also location_checksum_ uchar signature_[20]; uint32 file_size; // size of entire file uint32 header_size; // offset to start of next section uint32 endian_tag; uint32 link_size; // unused uint32 link_off; // unused uint32 map_off; // unused uint32 string_ids_size; // number of StringIds uint32 string_ids_off; // file offset of StringIds array uint32 type_ids_size; // number of TypeIds, we don't support more than 65535 uint32 type_ids_off; // file offset of TypeIds array uint32 proto_ids_size; // number of ProtoIds, we don't support more than 65535 uint32 proto_ids_off; // file offset of ProtoIds array uint32 field_ids_size; // number of FieldIds uint32 field_ids_off; // file offset of FieldIds array uint32 method_ids_size; // number of MethodIds uint32 method_ids_off; // file offset of MethodIds array uint32 class_defs_size; // number of ClassDefs uint32 class_defs_off; // file offset of ClassDef array uint32 data_size; // unused uint32 data_off; // unused} DexFileHeader;local int odexpad = 0;//// String IDs//typedef struct { uleb128 utf16_size
; string data
;} DexFileStringItem;typedef struct { uint string_data_off
; local int64 pos = FTell(); FSeek(odexpad + string_data_off); DexFileStringItem string_data
; FSeek(pos);} DexFileStringId
;string StringDataReader(DexFileStringId &i) { return i.string_data.data;}typedef struct (int size) { local int s = size; DexFileStringId string_ids[size]
;} DexFileStringIds
;string StringIDListRead(DexFileStringIds &l) { string s; s = SPrintf(s, "%d strings", l.s); return s;}//// type IDs//// read a value from the string tablestring StringIdRead(int id) { if(id == NO_INDEX) { return "NO_INDEX"; } local string s; SPrintf(s, "(0x%.X) \"%s\"", id, GetStringById(id)); return s;}// read a string from the string tablestring GetStringById(int id) { if(id == NO_INDEX) { return "NO_INDEX"; } if(exists(dex_string_ids.string_id[id])) { return dex_string_ids.string_id[id].string_data.data; } else { return "*** NO STRING"; }}string GetTypeById(struct DexFile& dexfile, int id) { if(id == NO_INDEX) { return "NO_INDEX"; } if(exists(dex_type_ids.type_id[id])) { return GetStringById2(dexfile, dexfile.dex_type_ids.type_id[id].descriptor_idx); } else { return "*** NO TYPE"; }}string GetLongTypeDescriptor(string descriptor) { local string desc = ""; local string post = ""; local int i = 0; local int len = Strlen(descriptor); // array descriptors while(descriptor[i] == '[') { post += "[]"; i++; if(i >= len) return "ERROR"; } if(descriptor[i] == 'L') { // fully qualified class descriptors i++; while(i < len) { if(descriptor[i] == '/') desc += "."; else if(descriptor[i] == ';') break; else desc += descriptor[i]; i++; } } else { // simple type descriptors switch(descriptor[i]) { case 'V': desc = "void"; break; case 'Z': desc = "boolean"; break; case 'B': desc = "byte"; break; case 'S': desc = "short"; break; case 'C': desc = "char"; break; case 'I': desc = "int"; break; case 'J': desc = "long"; break; case 'F': desc = "float"; break; case 'D': desc = "double"; break; } } return desc + post;}string GetLongTypeById(int id) { return GetLongTypeDescriptor(GetTypeById(id));}string GetMethodById(int id) { if(id == NO_INDEX) { return "NO_INDEX"; } if(exists(dex_method_ids.method_id[id])) { return MethodIdItemRead(dex_method_ids.method_id[id]); } else { return "*** NO METHOD"; }}string GetFieldById(int id) { if(id == NO_INDEX) { return "NO_INDEX"; } if(exists(dex_field_ids.field_id[id])) { return FieldIdItemRead(dex_field_ids.field_id[id]); } else { return "*** NO FIELD"; }}typedef struct { uint descriptor_idx
; local string name = GetStringById2(parentof(parentof(this)), descriptor_idx);} DexFileTypeId
;string GetStringById2(struct DexFile& dexfile, int id) { if(id == NO_INDEX) { return "NO_INDEX"; } if(exists(dexfile.dex_string_ids.string_ids[id])) { return dexfile.dex_string_ids.string_ids[id].string_data.data; } else { return "*** NO STRING"; }}string TypeIDRead(DexFileTypeId &i) { return i.name;}typedef struct (int size) { local int s = size; DexFileTypeId type_id[size]
;} DexFileTypeIds
;string TypeIDListRead(DexFileTypeIds &l) { string s; s = SPrintf(s, "%d types", l.s); return s;}// proto typedef struct { ushort type_idx
; local string type = GetLongTypeDescriptor(GetTypeById(parentof(parentof(parentof(parentof(this)))), return_type_idx));} DexFileTypeItem
;typedef struct { uint size
; DexFileTypeItem list[size]
;} DexFileTypeList
;string TypeItemRead(DexFileTypeItem &t) { return t.type;}string TypeItemListRead(DexFileTypeList &l) { string s = ""; string tmp; int i; for(i = 0; i < l.size; i++) { s += l.list[i].type; if(i+1 < l.size) { s += ", "; } } return s;}typedef struct { uint shorty_idx
; local string shorty = GetStringById2(parentof(parentof(this)), shorty_idx); uint return_type_idx
; local string return_type = GetLongTypeDescriptor(GetTypeById(parentof(parentof(this)), return_type_idx)); uint parameters_off
; if(parameters_off != 0) { local int64 pos = FTell(); FSeek(odexpad + parameters_off); DexFileTypeList parameters
; FSeek(pos); }} DexFileProtoId
;string ProtoIDItemRead(DexFileProtoId &i) { return GetPrototypeSignature(i);}string GetParameterListString(DexFileTypeList &l) { local string s = "("; local string tmp; local int i; for(i = 0; i < l.size; i++) { s += l.list[i].type; if(i+1 < l.size) { s += ", "; } } return s + ")";}string GetPrototypeSignature(DexFileProtoId &item) { string ret = item.return_type; string params = "()"; if(exists(item.parameters)) { params = GetParameterListString(item.parameters); } return ret + " " + params;}typedef struct (int size) { local int s = size; DexFileProtoId proto_id[size]
;} DexFileProtoIds
;string ProtoIDListRead(DexFileProtoIds &l) { string s; s = SPrintf(s, "%d protot ypes", l.s); return s;}//// fields//typedef struct { ushort class_idx
; local string class = GetLongTypeDescriptor(GetTypeById(parentof(parentof(this)), class_idx)); ushort type_idx
; local string type = GetLongTypeDescriptor(GetTypeById(parentof(parentof(this)), type_idx)); uint name_idx
; local string name = GetStringById2(parentof(parentof(this)), name_idx); } DexFileFieldId
;string FieldIdItemRead(DexFileFieldId &i) { return i.type + " " + i.class + " : " + i.name;}typedef struct (int size) { local int s = size; DexFileFieldId field_id[size]
;} DexFileFieldIds
;string FieldIDListRead(DexFileFieldIds &l) { string s; s = SPrintf(s, "%d fields", l.s); return s;}//// methods//typedef struct { ushort class_idx
; local string class = GetLongTypeDescriptor(GetTypeById(parentof(parentof(this)), class_idx)); ushort proto_idx
; local string proto = ""; uint name_idx
; local string name = GetStringById2(parentof(parentof(this)), name_idx);} DexFileMethodId
;string ProtoIdxRead(ushort p) { string s; SPrintf(s, "(0x%X) %s", p, GetPrototypeSignature(dex_proto_ids.proto_id[p])); return s;}string MethodIdItemRead(DexFileMethodId &m) {// local string retval = GetLongTypeDescriptor(GetTypeById(dex_proto_ids.proto_id[m.proto_idx].return_type_idx));// local string classname = GetLongTypeDescriptor(GetStringById(dex_type_ids.type_id[m.class_idx].descriptor_idx));// local string methodname = GetStringById(m.name_idx);// local string params = "()";// if(exists(dex_proto_ids.proto_id[m.proto_idx].parameters)) {// params = GetParameterListString(dex_proto_ids.proto_id[m.proto_idx].parameters);// } return m.proto + " " + m.class + "." + m.name;}typedef struct (int size) { local int s = size; DexFileMethodId method_id[size]
;} DexFileMethodIds
;string MethodIDListRead(DexFileMethodIds &l) { string s; s = SPrintf(s, "%d methods", l.s); return s;}// access flags. some of these mean different things for different items (class/field/method)typedef enum
{ ACC_PUBLIC = 0x1, ACC_PRIVATE = 0x2, ACC_PROTECTED = 0x4, ACC_STATIC = 0x8, ACC_FINAL = 0x10, ACC_SYNCHRONIZED = 0x20, ACC_VOLATILE = 0x40, // field //ACC_BRIDGE = 0x40, // method ACC_TRANSIENT = 0x80, // field //ACC_VARARGS = 0x80, // method ACC_NATIVE = 0x100, ACC_INTERFACE = 0x200, ACC_ABSTRACT = 0x400, ACC_STRICT = 0x800, ACC_SYNTHETIC = 0x1000, ACC_ANNOTATION = 0x2000, ACC_ENUM = 0x4000, ACC_CONSTRUCTOR = 0x10000, ACC_DECLARED_SYNCHRONIZED = 0x20000} ACCESS_FLAGS
;string AccessFlagsRead(ACCESS_FLAGS f) { string ret = ""; string flags = ""; ACCESS_FLAGS i = 1; while(i <= ACC_DECLARED_SYNCHRONIZED) { if (f & i) { flags += EnumToString(i) + " "; } i = i << 1; } SPrintf(ret, "(0x%X) %s", f, flags); return ret;}typedef enum { AF_CLASS, AF_FIELD, AF_METHOD} AF_TYPE;string GetFriendlyAccessFlag(int flag, AF_TYPE type) { switch (flag) { case ACC_PUBLIC: return "public"; case ACC_PRIVATE: return "private"; case ACC_PROTECTED: return "protected"; case ACC_STATIC: return "static"; case ACC_FINAL: return "final"; case ACC_SYNCHRONIZED: return "synchronized"; case ACC_VOLATILE: if(type == AF_FIELD) return "volatile"; else return "bridge"; // 0x40 is 'bridge' for methods case ACC_TRANSIENT: if(type == AF_FIELD) return "transient"; else return "varargs"; // 0x80 is 'varargs' for methods case ACC_NATIVE: return "native"; case ACC_INTERFACE: return "interface"; case ACC_ABSTRACT: return "abstract"; case ACC_STRICT: return "strict"; case ACC_SYNTHETIC: return "synthetic"; case ACC_ANNOTATION: return "annotation"; case ACC_ENUM: return "enum"; case ACC_CONSTRUCTOR: return "constructor"; case ACC_DECLARED_SYNCHRONIZED: return "declared-synchronized"; } return "ERROR";}string GetFriendlyAccessFlags(ACCESS_FLAGS f, AF_TYPE type) { string flags = ""; ACCESS_FLAGS i = 1; while(i <= ACC_DECLARED_SYNCHRONIZED) { if (f & i) { flags += GetFriendlyAccessFlag(i, type) + " "; } i = i << 1; } return flags;}typedef struct { uleb128 static_fields_size
; uleb128 instance_fields_size
; uleb128 direct_methods_size
; uleb128 virtual_methods_size
; if(uleb128_value(static_fields_size) > 0) {// encoded_field_list static_fields(uleb128_value(static_fields_size))
; } if(uleb128_value(instance_fields_size) > 0) {// encoded_field_list instance_fields(uleb128_value(instance_fields_size))
; } if(uleb128_value(direct_methods_size) > 0) {// encoded_method_list direct_methods(uleb128_value(direct_methods_size))
; } if(uleb128_value(virtual_methods_size) > 0) {// encoded_method_list virtual_methods(uleb128_value(virtual_methods_size))
; }} DexFileClassData
;string ClassDataItemRead(DexFileClassData &i) { local string s; SPrintf(s, "%i static fields, %i instance fields, %i direct methods, %i virtual methods", uleb128_value(i.static_fields_size), uleb128_value(i.instance_fields_size), uleb128_value(i.direct_methods_size), uleb128_value(i.virtual_methods_size)); return s;}typedef struct { local int64 pos; uint class_idx
; local string class = GetLongTypeDescriptor(GetTypeById(parentof(parentof(this)), class_idx)); ACCESS_FLAGS access_flags
; uint superclass_idx
; local string superclass = GetLongTypeDescriptor(GetTypeById(parentof(parentof(this)), superclass_idx)); uint interfaces_off
; if(interfaces_off != 0) { pos = FTell(); FSeek(odexpad + interfaces_off); // type_item_list interfaces
; FSeek(pos); } uint source_file_idx
; local string source_path = GetStringById2(parentof(parentof(this)), source_file_idx); uint annotations_off
; if(annotations_off != 0) { pos = FTell(); FSeek(odexpad + annotations_off); // annotations_directory_item annotations
; FSeek(pos); } uint class_data_off
; if(class_data_off != 0) { pos = FTell(); FSeek(odexpad + class_data_off); DexFileClassData class_data
; FSeek(pos); } uint static_values_off
; if(static_values_off != 0) { pos = FTell(); FSeek(odexpad + static_values_off); // struct encoded_array_item static_values
; FSeek(pos); }} DexFileClassDefItem
;string ClassDefItemRead(DexFileClassDefItem &i) { local string flags = GetFriendlyAccessFlags(i.access_flags, AF_CLASS); return flags + i.class;}typedef struct (int size) { local int s = size; DexFileClassDefItem class_def[size]
;} DexFileClassDefs
;string ClassDefItemListRead(DexFileClassDefs &l) { string s; s = SPrintf(s, "%d classes", l.s); return s;}//// map list//enum
TYPE_CODES { TYPE_HEADER_ITEM = 0x0000, TYPE_STRING_ID_ITEM = 0x0001, TYPE_TYPE_ID_ITEM = 0x0002, TYPE_PROTO_ID_ITEM = 0x0003, TYPE_FIELD_ID_ITEM = 0x0004, TYPE_METHOD_ID_ITEM = 0x0005, TYPE_CLASS_DEF_ITEM = 0x0006, TYPE_MAP_LIST = 0x1000, TYPE_TYPE_LIST = 0x1001, TYPE_ANNOTATION_SET_REF_LIST = 0x1002, TYPE_ANNOTATION_SET_ITEM = 0x1003, TYPE_CLASS_DATA_ITEM = 0x2000, TYPE_CODE_ITEM = 0x2001, TYPE_STRING_DATA_ITEM = 0x2002, TYPE_DEBUG_INFO_ITEM = 0x2003, TYPE_ANNOTATION_ITEM = 0x2004, TYPE_ENCODED_ARRAY_ITEM = 0x2005, TYPE_ANNOTATIONS_DIRECTORY_ITEM = 0x2006};typedef struct { TYPE_CODES type; ushort unused; uint size; uint offset; } DexFileMapItem
;string MapItemRead(DexFileMapItem &m) { string s; SPrintf(s, "%s", EnumToString(m.type)); return s;}typedef struct { uint size; DexFileMapItem list[size];} DexFileMapList
;string MapListTypeRead(DexFileMapList &t) { local string s; SPrintf(s, "%i items", t.size); return s;}//// dex file//typedef struct { DexFileHeader header; if(header.map_off != 0) { FSeek(odexpad + header.map_off); DexFileMapList dex_map_list
; local int i; for (i=0; i
; } else if (dex_map_list.list[i].type == TYPE_TYPE_ID_ITEM) { DexFileTypeIds dex_type_ids(header.type_ids_size)
; } else if (dex_map_list.list[i].type == TYPE_PROTO_ID_ITEM) { DexFileProtoIds dex_proto_ids(header.proto_ids_size)
; } else if (dex_map_list.list[i].type == TYPE_FIELD_ID_ITEM) { DexFileFieldIds dex_field_ids(header.field_ids_size)
; } else if (dex_map_list.list[i].type == TYPE_METHOD_ID_ITEM) { DexFileMethodIds dex_method_ids(header.method_ids_size)
; } else if (dex_map_list.list[i].type == TYPE_CLASS_DEF_ITEM) { DexFileClassDefs dex_class_defs(header.class_defs_size)
; } else { // uint UNPROCESS_TYPE = dex_map_list.list[i].type; } } }} DexFile;typedef struct { uint32 code_offset_; uint32 frame_size_in_bytes_; uint32 core_spill_mask_; uint32 fp_spill_mask_; uint32 mapping_table_offset_; uint32 vmap_table_offset_; uint32 gc_map_offset_; local uint32 off = code_offset_ & ~0x1; if (off > 0) { Printf("code_offset [%x][%x] = %x\n", code_offset_, off, off + 0x1000); }} OatMethodOffsets;typedef struct (int index) { uint32 status; local int methodCount = getClassMethodCount(parentof(parentof(this)), index); local string name = getClassName(parentof(parentof(this)), index); if (methodCount > 0) { OatMethodOffsets methodOffset[methodCount]
; }} OatClass
;string ReadOatClass(OatClass &c) { return c.name;}typedef struct (int size) { local int total = size; local int idx; for (idx=0; idx
;string ReadOatClasses(OatClasses &oc) { local string s; SPrintf(s, "%i classes", oc.total); return s;}string getClassName(struct OatDexFile& oatfile, int classIdx) { if (exists(oatfile.dex_file.dex_class_defs.class_def[classIdx])) { return oatfile.dex_file.dex_class_defs.class_def[classIdx].class; } return "** NO NAME **";}int getClassMethodCount(struct OatDexFile& oatfile, int classIdx) { if (exists(oatfile.dex_file.dex_class_defs.class_def[classIdx])) { if (exists(oatfile.dex_file.dex_class_defs.class_def[classIdx].class_data)) { local int dirNum = uleb128_value(oatfile.dex_file.dex_class_defs.class_def[classIdx].class_data.direct_methods_size); local int virNum = uleb128_value(oatfile.dex_file.dex_class_defs.class_def[classIdx].class_data.virtual_methods_size); return dirNum + virNum; } } return 0;}typedef struct { uint32 dex_file_location_size; char dex_file_location_data[dex_file_location_size]; uint32 dex_file_checksum; uint32 dex_file_offset; local quad off = FTell(); local quad method_count = (oatdata_off + dex_file_offset - off) / sizeof(uint32); uint32 method_offs[method_count]; odexpad = oatdata_off + dex_file_offset; FSeek(oatdata_off + dex_file_offset); DexFile dex_file; FSeek(oatdata_off + dex_file_offset + dex_file.header.file_size); OatClasses oat_classes(dex_file.header.class_defs_size) ; } OatDexFile
;typedef struct { char magic[4]; char version[4]; uint32 checksum; InstructionSet instruction_set; uint32 dex_file_count; uint32 executable_offset_; uint32 interpreter_to_interpreter_bridge_offset_; uint32 interpreter_to_compiled_code_bridge_offset_; uint32 jni_dlsym_lookup_offset_; uint32 portable_resolution_trampoline_offset_; uint32 portable_to_interpreter_bridge_offset_; uint32 quick_resolution_trampoline_offset_; uint32 quick_to_interpreter_bridge_offset_; uint32 image_file_location_oat_checksum_; uint32 image_file_location_oat_data_begin_; uint32 image_file_location_size; char image_file_location_data[image_file_location_size];} OatHeader;struct { Elf32_Ehdr elf_header; if (elf_header.e_phnum > 0) { FSeek(elf_header.e_phoff); Elf32_Phdr elf_program_header[elf_header.e_phnum]; } local uint soff = elf_header.e_shoff + elf_header.e_shentsize * elf_header.e_shstrndx; section_name_off = ReadUInt(soff + 3 * sizeof( Elf32_Word ) + sizeof( Elf32_Addr )); // Printf("section_name_off=%x", section_name_off); if (elf_header.e_shnum > 0) { FSeek(elf_header.e_shoff); Elf32_Shdr elf_section_header[elf_header.e_shnum]
; local uint strindex = FindNamedSection(".dynstr"); dynsym_name_off = elf_section_header[strindex].sh_offset; local uint symindex = FindNamedSection(".dynsym"); local uint symcount = elf_section_header[symindex].sh_size / sizeof(Elf32_Sym_Fixed); FSeek(elf_section_header[symindex].sh_offset); // dynsym Elf32_Sym symtab[symcount]
; // dynstr if (elf_section_header[strindex].sh_size > 0) { local quad off = FTell(); FSeek( dynsym_name_off ); char dynstr[elf_section_header[strindex].sh_size]; FSeek( off ); } // hash local uint hashindex = FindNamedSection(".hash"); FSeek( elf_section_header[hashindex].sh_offset ); Elf32_Word hash[elf_section_header[hashindex].sh_size]; // rodata local uint rodataindex = FindNamedSection(".rodata"); FSeek( elf_section_header[rodataindex].sh_offset ); uchar rodata[elf_section_header[rodataindex].sh_size]; // text local uint textindex = FindNamedSection(".text"); FSeek( elf_section_header[textindex].sh_offset ); uchar text[elf_section_header[textindex].sh_size]; // dynamic local uint dynamicindex = FindNamedSection(".dynamic"); FSeek( elf_section_header[dynamicindex].sh_offset ); uchar dynamic[elf_section_header[dynamicindex].sh_size]; // shstrtab local uint shstrtabindex = FindNamedSection(".shstrtab"); FSeek( elf_section_header[shstrtabindex].sh_offset ); char shstrtab[elf_section_header[shstrtabindex].sh_size]; } if (oatdata_off > 0) { FSeek(oatdata_off); OatHeader oat_header; OatDexFile dex_files[oat_header.dex_file_count]; }} file;

 

最后:

模版让使用者有过优化或改进,请反馈给我,在这里先感谢一下。

分类:
242人阅读
(4)

前面写了一篇博客大致描述了一下Image文件的结构,本文将接下来简单描述一下Oat文件的大致结构。

和前面一样,还是来看一下代码,代码非常复杂,为了保证大家不分心,我会尽量去除一些冗余的部分,只留下主体部分。

好了,Oat文件的读取是通过OatFile::ElfFileOpen(art\runtime\Oat_file.cc)进行的:

[cpp]
  1. bool OatFile::ElfFileOpen(File* file, byte* requested_base, bool writable, bool executable) {  
  2.   elf_file_.reset(ElfFile::Open(file, writable, true));  
  3.   if (elf_file_.get() == NULL) {  
  4.     if (writable) {  
  5.       PLOG(WARNING) << "Failed to open ELF file for " << file->GetPath();  
  6.     }  
  7.     return false;  
  8.   }  
  9.   ......  
bool OatFile::ElfFileOpen(File* file, byte* requested_base, bool writable, bool executable) {  elf_file_.reset(ElfFile::Open(file, writable, true));  if (elf_file_.get() == NULL) {    if (writable) {      PLOG(WARNING) << "Failed to open ELF file for " << file->GetPath();    }    return false;  }  ......
咦,不是oat文件吗?怎么冒出来了elf文件?其实所谓的oat文件是影藏在elf文件中的,先卖个关子,后面再具体说明。

代码逻辑很简单,先通过ElfFile::Open函数打开文件,然后设置到成员变量elf_file_中,如果为空代表加载elf文件失败,直接退出。

下面看看ElfFile::Open函数(art\runtime\Elf_file.cc):

[cpp]
  1. ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only) {  
  2.   UniquePtr<ElfFile> elf_file(new ElfFile());  
  3.   if (!elf_file->Setup(file, writable, program_header_only)) {  
  4.     return NULL;  
  5.   }  
  6.   return elf_file.release();  
  7. }  
ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only) {  UniquePtr
elf_file(new ElfFile()); if (!elf_file->Setup(file, writable, program_header_only)) { return NULL; } return elf_file.release();}
也很简单,创建一个elf_file实例,然后调用其Setup函数,如果失败的话返回NULL,如果成功就返回创建的elf_file实例。

接下来,看看ElfFile::Setup函数的实现:

[cpp]
  1. bool ElfFile::Setup(File* file, bool writable, bool program_header_only) {  
  2.   CHECK(file != NULL);  
  3.   file_ = file;  
  4.   writable_ = writable;  
  5.   program_header_only_ = program_header_only;  
  6.   
  7.   int prot;  
  8.   int flags;  
  9.   if (writable_) {  
  10.     prot = PROT_READ | PROT_WRITE;  
  11.     flags = MAP_SHARED;  
  12.   } else {  
  13.     prot = PROT_READ;  
  14.     flags = MAP_PRIVATE;  
  15.   }  
  16.   int64_t file_length = file_->GetLength();  
  17.   if (file_length < 0) {  
  18.     errno = -file_length;  
  19.     PLOG(WARNING) << "Failed to get length of file: " << file_->GetPath() << " fd=" << file_->Fd();  
  20.     return false;  
  21.   }  
  22.   if (file_length < sizeof(llvm::ELF::Elf32_Ehdr)) {  
  23.     if (writable) {  
  24.       LOG(WARNING) << "File size of " << file_length  
  25.                    << " bytes not large enough to contain ELF header of "  
  26.                    << sizeof(llvm::ELF::Elf32_Ehdr) << " bytes: " << file_->GetPath();  
  27.     }  
  28.     return false;  
  29.   }  
  30.   
  31.   if (program_header_only) {  
  32.     // first just map ELF header to get program header size information   
  33.     size_t elf_header_size = sizeof(llvm::ELF::Elf32_Ehdr);  
  34.     if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, file_->Fd(), 0))) {  
  35.       return false;  
  36.     }  
  37.     // then remap to cover program header   
  38.     size_t program_header_size = header_->e_phoff + (header_->e_phentsize * header_->e_phnum);  
  39.     if (file_length < program_header_size) {  
  40.       LOG(WARNING) << "File size of " << file_length  
  41.                    << " bytes not large enough to contain ELF program header of "  
  42.                    << program_header_size << " bytes: " << file_->GetPath();  
  43.       return false;  
  44.     }  
  45.     if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file_->Fd(), 0))) {  
  46.       LOG(WARNING) << "Failed to map ELF program headers: " << file_->GetPath();  
  47.       return false;  
  48.     }  
  49.   } else {  
  50.     ......  
  51.     }  
  52.   }  
  53.   
  54.   // Either way, the program header is relative to the elf header   
  55.   program_headers_start_ = Begin() + GetHeader().e_phoff;  
  56.   
  57.   if (!program_header_only) {  
  58.      ......  
  59.   }  
  60.   return true;  
  61. }  
bool ElfFile::Setup(File* file, bool writable, bool program_header_only) {  CHECK(file != NULL);  file_ = file;  writable_ = writable;  program_header_only_ = program_header_only;  int prot;  int flags;  if (writable_) {    prot = PROT_READ | PROT_WRITE;    flags = MAP_SHARED;  } else {    prot = PROT_READ;    flags = MAP_PRIVATE;  }  int64_t file_length = file_->GetLength();  if (file_length < 0) {    errno = -file_length;    PLOG(WARNING) << "Failed to get length of file: " << file_->GetPath() << " fd=" << file_->Fd();    return false;  }  if (file_length < sizeof(llvm::ELF::Elf32_Ehdr)) {    if (writable) {      LOG(WARNING) << "File size of " << file_length                   << " bytes not large enough to contain ELF header of "                   << sizeof(llvm::ELF::Elf32_Ehdr) << " bytes: " << file_->GetPath();    }    return false;  }  if (program_header_only) {    // first just map ELF header to get program header size information    size_t elf_header_size = sizeof(llvm::ELF::Elf32_Ehdr);    if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, file_->Fd(), 0))) {      return false;    }    // then remap to cover program header    size_t program_header_size = header_->e_phoff + (header_->e_phentsize * header_->e_phnum);    if (file_length < program_header_size) {      LOG(WARNING) << "File size of " << file_length                   << " bytes not large enough to contain ELF program header of "                   << program_header_size << " bytes: " << file_->GetPath();      return false;    }    if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file_->Fd(), 0))) {      LOG(WARNING) << "Failed to map ELF program headers: " << file_->GetPath();      return false;    }  } else {    ......    }  }  // Either way, the program header is relative to the elf header  program_headers_start_ = Begin() + GetHeader().e_phoff;  if (!program_header_only) {     ......  }  return true;}
传进来的三个参数,第一个参数file表示要打开的elf文件,第二个参数writable表示映射到内存中后是否允许写入,第三个参数program_header_only表示是否只映射elf的Program Headers,当然elf头是无论如何要映射的。这个函数比较大,为了便于分析,由于传进来的参数program_header_only是true,我删除了代码没有走到的地方。

程序首先判断是否允许写入,并且设置相应的参数,这些都是mmap要用到的。然后是一些错误判断,如文件大小不能为负数,并且文件头的大小不能大于文件整体的长度。下面就是动真格的了,先计算一下elf头的大小,这个值是固定的,然后把这个elf头映射到内存中。

接下来计算elf头包含了Program Header后的长度,因为elf头中记录了Program Header相对于文件初始位置的偏移(e_phoff),每一项所占据空间的大小(e_phentsize)和有多少项组成(e_phnum),并且Program Header肯定是接在elf头之后的,所以非常好计算。

再接下来,又重新映射了一下MemMap,把Program Header包含了进来。为什么要映射两次呢?答案很简单,因为不读elf头的话,没法知道Program Header到底有多长。

最后初始化了成员变量programs_headers_start_,很简单,就是文件起始地址加上Program Header偏移。初始化后,ElfFile::GetProgramHeader函数才可以用,后面会用到。

那到底是怎么映射的呢?从代码来看,具体是通过MemMap::MapFile(art\runtime\Mem_map.cc)来映射的,然后调用SetMap来设置自己的成员变量。首先来看MemMap::MapFile:

[cpp]
  1. static MemMap* MapFile(size_t byte_count, int prot, int flags, int fd, off_t start) {  
  2.     return MapFileAtAddress(NULL, byte_count, prot, flags, fd, start, false);  
  3.   }  
static MemMap* MapFile(size_t byte_count, int prot, int flags, int fd, off_t start) {    return MapFileAtAddress(NULL, byte_count, prot, flags, fd, start, false);  }
直接调用自己的MemMap::MapFileAtAddress,但是第一个参数传NULL,也就是无所谓映射到哪,接下来看MemMap::MapFileAtAddress:

[cpp]
  1. MemMap* MemMap::MapFileAtAddress(byte* addr, size_t byte_count,  
  2.                                  int prot, int flags, int fd, off_t start, bool reuse) {  
  3.   CHECK_NE(0, prot);  
  4.   CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE));  
  5.   if (byte_count == 0) {  
  6.     return new MemMap("file", NULL, 0, NULL, 0, prot);  
  7.   }  
  8.   // Adjust 'offset' to be page-aligned as required by mmap.   
  9.   int page_offset = start % kPageSize;  
  10.   off_t page_aligned_offset = start - page_offset;  
  11.   // Adjust 'byte_count' to be page-aligned as we will map this anyway.   
  12.   size_t page_aligned_byte_count = RoundUp(byte_count + page_offset, kPageSize);  
  13.   // The 'addr' is modified (if specified, ie non-null) to be page aligned to the file but not   
  14.   // necessarily to virtual memory. mmap will page align 'addr' for us.   
  15.   byte* page_aligned_addr = (addr == NULL) ? NULL : (addr - page_offset);  
  16.   if (!reuse) {  
  17.     // reuse means it is okay that it overlaps an existing page mapping.   
  18.     // Only use this if you actually made the page reservation yourself.   
  19.     CheckMapRequest(page_aligned_addr, page_aligned_byte_count);  
  20.   } else {  
  21.     CHECK(addr != NULL);  
  22.   }  
  23.   byte* actual = reinterpret_cast<byte*>(mmap(page_aligned_addr,  
  24.                                               page_aligned_byte_count,  
  25.                                               prot,  
  26.                                               flags,  
  27.                                               fd,  
  28.                                               page_aligned_offset));  
  29.   if (actual == MAP_FAILED) {  
  30.     std::string maps;  
  31.     ReadFileToString("/proc/self/maps", &maps);  
  32.     PLOG(ERROR) << "mmap(" << reinterpret_cast<void*>(page_aligned_addr)  
  33.                 << ", " << page_aligned_byte_count  
  34.                 << ", " << prot << ", " << flags << ", " << fd << ", " << page_aligned_offset  
  35.                 << ") failed\n" << maps;  
  36.     return NULL;  
  37.   }  
  38.   return new MemMap("file", actual + page_offset, byte_count, actual, page_aligned_byte_count,  
  39.                     prot);  
  40. }  
MemMap* MemMap::MapFileAtAddress(byte* addr, size_t byte_count,                                 int prot, int flags, int fd, off_t start, bool reuse) {  CHECK_NE(0, prot);  CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE));  if (byte_count == 0) {    return new MemMap("file", NULL, 0, NULL, 0, prot);  }  // Adjust 'offset' to be page-aligned as required by mmap.  int page_offset = start % kPageSize;  off_t page_aligned_offset = start - page_offset;  // Adjust 'byte_count' to be page-aligned as we will map this anyway.  size_t page_aligned_byte_count = RoundUp(byte_count + page_offset, kPageSize);  // The 'addr' is modified (if specified, ie non-null) to be page aligned to the file but not  // necessarily to virtual memory. mmap will page align 'addr' for us.  byte* page_aligned_addr = (addr == NULL) ? NULL : (addr - page_offset);  if (!reuse) {    // reuse means it is okay that it overlaps an existing page mapping.    // Only use this if you actually made the page reservation yourself.    CheckMapRequest(page_aligned_addr, page_aligned_byte_count);  } else {    CHECK(addr != NULL);  }  byte* actual = reinterpret_cast
(mmap(page_aligned_addr, page_aligned_byte_count, prot, flags, fd, page_aligned_offset)); if (actual == MAP_FAILED) { std::string maps; ReadFileToString("/proc/self/maps", &maps); PLOG(ERROR) << "mmap(" << reinterpret_cast
(page_aligned_addr) << ", " << page_aligned_byte_count << ", " << prot << ", " << flags << ", " << fd << ", " << page_aligned_offset << ") failed\n" << maps; return NULL; } return new MemMap("file", actual + page_offset, byte_count, actual, page_aligned_byte_count, prot);}
首先还是做一些出错判断,接下来计算映射到内存中的真正大小。不是传入文件大小了嘛,为什么还要计算要映射的大小?因为内存映射是以页为单位的,如果要映射的地址不是4K对齐的,就需要重新结算大小。扯远了,接下来就真的调用mmap,把文件映射到内存,返回的actual表示实际上映射到的内存地址,然后创建一个MemMap实例(MemMap::MapFileAtAddress函数是静态的),并初始化各个变量,然后返回。这样看来,MemMap其实就是代表了从文件映射到内存中的一段空间以及其属性。

好,接下来回过来看ElfFile::SetMap:

[cpp]
  1. bool ElfFile::SetMap(MemMap* map) {  
  2.   if (map == NULL) {  
  3.     // MemMap::Open should have already logged   
  4.     return false;  
  5.   }  
  6.   map_.reset(map);  
  7.   CHECK(map_.get() != NULL) << file_->GetPath();  
  8.   CHECK(map_->Begin() != NULL) << file_->GetPath();  
  9.   
  10.   header_ = reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(map_->Begin());  
  11.   if ((llvm::ELF::ElfMagic[0] != header_->e_ident[llvm::ELF::EI_MAG0])  
  12.       || (llvm::ELF::ElfMagic[1] != header_->e_ident[llvm::ELF::EI_MAG1])  
  13.       || (llvm::ELF::ElfMagic[2] != header_->e_ident[llvm::ELF::EI_MAG2])  
  14.       || (llvm::ELF::ElfMagic[3] != header_->e_ident[llvm::ELF::EI_MAG3])) {  
  15.     LOG(WARNING) << "Failed to find ELF magic in " << file_->GetPath()  
  16.                  << ": " << std::hex  
  17.                  << static_cast<uint8_t>(header_->e_ident[llvm::ELF::EI_MAG0])  
  18.                  << static_cast<uint8_t>(header_->e_ident[llvm::ELF::EI_MAG1])  
  19.                  << static_cast<uint8_t>(header_->e_ident[llvm::ELF::EI_MAG2])  
  20.                  << static_cast<uint8_t>(header_->e_ident[llvm::ELF::EI_MAG3]);  
  21.     return false;  
  22.   }  
  23.   
  24.   ......  
  25.     
  26.   return true;  
  27. }  
bool ElfFile::SetMap(MemMap* map) {  if (map == NULL) {    // MemMap::Open should have already logged    return false;  }  map_.reset(map);  CHECK(map_.get() != NULL) << file_->GetPath();  CHECK(map_->Begin() != NULL) << file_->GetPath();  header_ = reinterpret_cast
(map_->Begin()); if ((llvm::ELF::ElfMagic[0] != header_->e_ident[llvm::ELF::EI_MAG0]) || (llvm::ELF::ElfMagic[1] != header_->e_ident[llvm::ELF::EI_MAG1]) || (llvm::ELF::ElfMagic[2] != header_->e_ident[llvm::ELF::EI_MAG2]) || (llvm::ELF::ElfMagic[3] != header_->e_ident[llvm::ELF::EI_MAG3])) { LOG(WARNING) << "Failed to find ELF magic in " << file_->GetPath() << ": " << std::hex << static_cast
(header_->e_ident[llvm::ELF::EI_MAG0]) << static_cast
(header_->e_ident[llvm::ELF::EI_MAG1]) << static_cast
(header_->e_ident[llvm::ELF::EI_MAG2]) << static_cast
(header_->e_ident[llvm::ELF::EI_MAG3]); return false; } ...... return true;}
非常简单,无非就是设置自己的成员变量map_到上面新创建的MemMap,将成员变量header_指到加载进来的elf头的位置,并检查最初的四个字节是不是符合elf的magic code。所以,必须要SetMap之后,ElfFile的很多函数才可以用,否则header_指向的值是不对的。

 而这里的magic code就是标准的elf文件标识,即:

[cpp]
  1. llvm::ELF::ElfMagic[0] = 0x7f;  
  2. llvm::ELF::ElfMagic[1] = 'E';  
  3. llvm::ELF::ElfMagic[2] = 'L';  
  4. llvm::ELF::ElfMagic[3] = 'F';  
llvm::ELF::ElfMagic[0] = 0x7f;llvm::ELF::ElfMagic[1] = 'E';llvm::ELF::ElfMagic[2] = 'L';llvm::ELF::ElfMagic[3] = 'F';
好了,绕了一大圈,其实就是把elf的头以及Program Header加载进了内存,我们回到OatFile::ElfFileOpen接着分析:

[cpp]
  1. bool loaded = elf_file_->Load(executable);  
  2. if (!loaded) {  
  3.   LOG(WARNING) << "Failed to load ELF file " << file->GetPath();  
  4.   return false;  
  5. }  
bool loaded = elf_file_->Load(executable);  if (!loaded) {    LOG(WARNING) << "Failed to load ELF file " << file->GetPath();    return false;  }
接下来主要是调用了ElfFile::Load函数,如果失败就返回false。好接下来看ElfFile::Load:

[cpp]
  1. bool ElfFile::Load(bool executable) {  
  2.   CHECK(program_header_only_) << file_->GetPath();  
  3.   for (llvm::ELF::Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) {  
  4.     llvm::ELF::Elf32_Phdr& program_header = GetProgramHeader(i);  
  5.   
  6.     // Record .dynamic header information for later use   
  7.     if (program_header.p_type == llvm::ELF::PT_DYNAMIC) {  
  8.       dynamic_program_header_ = &program_header;  
  9.       continue;  
  10.     }  
  11.   
  12.     // Not something to load, move on.   
  13.     if (program_header.p_type != llvm::ELF::PT_LOAD) {  
  14.       continue;  
  15.     }  
  16.   
  17.     int64_t file_length = file_->GetLength();  
  18.     if (program_header.p_vaddr == 0) {  
  19.       std::string reservation_name("ElfFile reservation for ");  
  20.       reservation_name += file_->GetPath();  
  21.       UniquePtr<MemMap> reserve(MemMap::MapAnonymous(reservation_name.c_str(),  
  22.                                                      NULL, GetLoadedSize(), PROT_NONE));  
  23.       CHECK(reserve.get() != NULL) << file_->GetPath();  
  24.       base_address_ = reserve->Begin();  
  25.       segments_.push_back(reserve.release());  
  26.     }  
  27.     // empty segment, nothing to map   
  28.     if (program_header.p_memsz == 0) {  
  29.       continue;  
  30.     }  
  31.     ......  
bool ElfFile::Load(bool executable) {  CHECK(program_header_only_) << file_->GetPath();  for (llvm::ELF::Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) {    llvm::ELF::Elf32_Phdr& program_header = GetProgramHeader(i);    // Record .dynamic header information for later use    if (program_header.p_type == llvm::ELF::PT_DYNAMIC) {      dynamic_program_header_ = &program_header;      continue;    }    // Not something to load, move on.    if (program_header.p_type != llvm::ELF::PT_LOAD) {      continue;    }    int64_t file_length = file_->GetLength();    if (program_header.p_vaddr == 0) {      std::string reservation_name("ElfFile reservation for ");      reservation_name += file_->GetPath();      UniquePtr
reserve(MemMap::MapAnonymous(reservation_name.c_str(), NULL, GetLoadedSize(), PROT_NONE)); CHECK(reserve.get() != NULL) << file_->GetPath(); base_address_ = reserve->Begin(); segments_.push_back(reserve.release()); } // empty segment, nothing to map if (program_header.p_memsz == 0) { continue; } ......
代码很长,先只列出前面的一部分。可以看出程序先获得Program Header内到底有多少项,然后逐项遍历。为了便于理解,我挑了一个例子,就是系统的Boot Oat(system@framework@boot.oat)文件,用readelf可以得到其Program Header如下:

可以看到其一共包含5项,第一项表示的是Program Header本身在要映射到内存中的大小和位置。第二项到第四项是三个要加载进内存的段,为什么要分三个?因为他们的属性不同。最后一个指向的是动态节区,其有很多项组成。其它的项先不管,有一个特别重要的项是SYMTAB,即符号表节,这个节中记录了几个符号已经其对应的属性和值。对于内含oat的elf文件来说,一共有三个非常重要的符号分别是oatdata,oatexec和oatlastword,具体用处后面再解释。

细心的读者有没有发现第四项和第五项的内容除了类型不同外,其它都完全一样。

好了,还是回来看代码。程序会遍历Program Header中的所有项。对各项,首先,看该该项是不是PT_DYNAMIC类型的(第五项),如果是就用来初始化dynamic_program_header_成员变量。奇怪的是直接就赋值了,没有把其指定的段加载进内存中?答案其实前面提到过了,在处理第四项的时候已经将其加载进内存中的,而第五项和第四项所有属性都一样。

接下来,判断该项的类型是不是PT_LOAD,如果不是,直接忽略,即非PT_LOAD类型的段不需要加载。

再下来,判断了一下该项指定的虚拟地址是否是0。如果为0的话,就调用MemMap::MapAnonymous来加载。看看前面的例子,咦,怎么没有虚拟地址为0的段?我们再随便写 一个HelloWorld程序,装上手机,拿出转换过后的oat文件看看,通过readelf,其Program Header如下:

看到第二项了吧,真的有一个PT_LOAD段的虚拟地址指定的是0。顺便说一句,虚拟地址为0的项一定是Program Header各个PT_LOAD类型项的第一项。那么有虚拟地址为0的段和没有虚拟地址为0的段,处理起来有什么区别呢?

首先,我们看看有的情况,接着看MemMap::MapAnonymous:

[cpp]
  1. MemMap* MemMap::MapAnonymous(const char* name, byte* addr, size_t byte_count, int prot) {  
  2.   if (byte_count == 0) {  
  3.     return new MemMap(name, NULL, 0, NULL, 0, prot);  
  4.   }  
  5.   size_t page_aligned_byte_count = RoundUp(byte_count, kPageSize);  
  6.   CheckMapRequest(addr, page_aligned_byte_count);  
  7.   
  8. #ifdef USE_ASHMEM   
  9.   // android_os_Debug.cpp read_mapinfo assumes all ashmem regions associated with the VM are   
  10.   // prefixed "dalvik-".   
  11.   std::string debug_friendly_name("dalvik-");  
  12.   debug_friendly_name += name;  
  13.   ScopedFd fd(ashmem_create_region(debug_friendly_name.c_str(), page_aligned_byte_count));  
  14.   int flags = MAP_PRIVATE;  
  15.   if (fd.get() == -1) {  
  16.     PLOG(ERROR) << "ashmem_create_region failed (" << name << ")";  
  17.     return NULL;  
  18.   }  
  19. #else   
  20.   ScopedFd fd(-1);  
  21.   int flags = MAP_PRIVATE | MAP_ANONYMOUS;  
  22. #endif   
  23.   
  24.   byte* actual = reinterpret_cast<byte*>(mmap(addr, page_aligned_byte_count, prot, flags, fd.get(), 0));  
  25.   if (actual == MAP_FAILED) {  
  26.     std::string maps;  
  27.     ReadFileToString("/proc/self/maps", &maps);  
  28.     PLOG(ERROR) << "mmap(" << reinterpret_cast<void*>(addr) << ", " << page_aligned_byte_count  
  29.                 << ", " << prot << ", " << flags << ", " << fd.get() << ", 0) failed for " << name  
  30.                 << "\n" << maps;  
  31.     return NULL;  
  32.   }  
  33.   return new MemMap(name, actual, byte_count, actual, page_aligned_byte_count, prot);  
  34. }  
MemMap* MemMap::MapAnonymous(const char* name, byte* addr, size_t byte_count, int prot) {  if (byte_count == 0) {    return new MemMap(name, NULL, 0, NULL, 0, prot);  }  size_t page_aligned_byte_count = RoundUp(byte_count, kPageSize);  CheckMapRequest(addr, page_aligned_byte_count);#ifdef USE_ASHMEM  // android_os_Debug.cpp read_mapinfo assumes all ashmem regions associated with the VM are  // prefixed "dalvik-".  std::string debug_friendly_name("dalvik-");  debug_friendly_name += name;  ScopedFd fd(ashmem_create_region(debug_friendly_name.c_str(), page_aligned_byte_count));  int flags = MAP_PRIVATE;  if (fd.get() == -1) {    PLOG(ERROR) << "ashmem_create_region failed (" << name << ")";    return NULL;  }#else  ScopedFd fd(-1);  int flags = MAP_PRIVATE | MAP_ANONYMOUS;#endif  byte* actual = reinterpret_cast
(mmap(addr, page_aligned_byte_count, prot, flags, fd.get(), 0)); if (actual == MAP_FAILED) { std::string maps; ReadFileToString("/proc/self/maps", &maps); PLOG(ERROR) << "mmap(" << reinterpret_cast
(addr) << ", " << page_aligned_byte_count << ", " << prot << ", " << flags << ", " << fd.get() << ", 0) failed for " << name << "\n" << maps; return NULL; } return new MemMap(name, actual, byte_count, actual, page_aligned_byte_count, prot);}
这个函数比较容易理解,不多做解释。传进来的参数addr为NULL,所以调用过后的作用其实就是在内存中预留了一段内存段,并且起始地址没指定,表明可以分配到任何地方。

那到底要分配多大呢,来看ElfFile::GetLoadedSize:

[cpp]
  1. size_t ElfFile::GetLoadedSize() {  
  2.   llvm::ELF::Elf32_Addr min_vaddr = 0xFFFFFFFFu;  
  3.   llvm::ELF::Elf32_Addr max_vaddr = 0x00000000u;  
  4.   for (llvm::ELF::Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) {  
  5.     llvm::ELF::Elf32_Phdr& program_header = GetProgramHeader(i);  
  6.     if (program_header.p_type != llvm::ELF::PT_LOAD) {  
  7.       continue;  
  8.     }  
  9.     llvm::ELF::Elf32_Addr begin_vaddr = program_header.p_vaddr;  
  10.     if (begin_vaddr < min_vaddr) {  
  11.        min_vaddr = begin_vaddr;  
  12.     }  
  13.     llvm::ELF::Elf32_Addr end_vaddr = program_header.p_vaddr + program_header.p_memsz;  
  14.     if (end_vaddr > max_vaddr) {  
  15.       max_vaddr = end_vaddr;  
  16.     }  
  17.   }  
  18.   min_vaddr = RoundDown(min_vaddr, kPageSize);  
  19.   max_vaddr = RoundUp(max_vaddr, kPageSize);  
  20.   CHECK_LT(min_vaddr, max_vaddr) << file_->GetPath();  
  21.   size_t loaded_size = max_vaddr - min_vaddr;  
  22.   return loaded_size;  
  23. }  
size_t ElfFile::GetLoadedSize() {  llvm::ELF::Elf32_Addr min_vaddr = 0xFFFFFFFFu;  llvm::ELF::Elf32_Addr max_vaddr = 0x00000000u;  for (llvm::ELF::Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) {    llvm::ELF::Elf32_Phdr& program_header = GetProgramHeader(i);    if (program_header.p_type != llvm::ELF::PT_LOAD) {      continue;    }    llvm::ELF::Elf32_Addr begin_vaddr = program_header.p_vaddr;    if (begin_vaddr < min_vaddr) {       min_vaddr = begin_vaddr;    }    llvm::ELF::Elf32_Addr end_vaddr = program_header.p_vaddr + program_header.p_memsz;    if (end_vaddr > max_vaddr) {      max_vaddr = end_vaddr;    }  }  min_vaddr = RoundDown(min_vaddr, kPageSize);  max_vaddr = RoundUp(max_vaddr, kPageSize);  CHECK_LT(min_vaddr, max_vaddr) << file_->GetPath();  size_t loaded_size = max_vaddr - min_vaddr;  return loaded_size;}
该程序遍历所有Program Header项,略去所有PT_LOAD段,计算剩下的所有项中起始地址最小的,还有结束地址加上该段长度后最大的地址,然后按照页大小调整一下,最后用得到的最大值减去最小值。其实很简单了,就是该elf文件的全部大小。

所以如果有虚拟地址为0的段话,就是先按照文件的大小随便在内存中映射一段内存,不指定起始地址,然后设置变量base_address_为该段的起始地址。那么如果没有虚拟地址为0的段,会怎么样呢?这是base_address_就是0。好,接着看剩下的部分:

[cpp]
  1. byte* p_vaddr = base_address_ + program_header.p_vaddr;  
  2. int prot = 0;  
  3. if (executable && ((program_header.p_flags & llvm::ELF::PF_X) != 0)) {  
  4.   prot |= PROT_EXEC;  
  5. }  
  6. if ((program_header.p_flags & llvm::ELF::PF_W) != 0) {  
  7.   prot |= PROT_WRITE;  
  8. }  
  9. if ((program_header.p_flags & llvm::ELF::PF_R) != 0) {  
  10.   prot |= PROT_READ;  
  11. }  
  12. int flags = MAP_FIXED;  
  13. if (writable_) {  
  14.   prot |= PROT_WRITE;  
  15.   flags |= MAP_SHARED;  
  16. else {  
  17.   flags |= MAP_PRIVATE;  
  18. }  
  19. if (file_length < (program_header.p_offset + program_header.p_memsz)) {  
  20.   LOG(WARNING) << "File size of " << file_length  
  21.                << " bytes not large enough to contain ELF segment " << i  
  22.                << " of " << (program_header.p_offset + program_header.p_memsz)  
  23.                << " bytes: " << file_->GetPath();  
  24.   return false;  
  25. }  
  26. UniquePtr<MemMap> segment(MemMap::MapFileAtAddress(p_vaddr,  
  27.                                                    program_header.p_memsz,  
  28.                                                    prot, flags, file_->Fd(),  
  29.                                                    program_header.p_offset,  
  30.                                                    true));  
  31. CHECK(segment.get() != NULL) << file_->GetPath();  
  32. CHECK_EQ(segment->Begin(), p_vaddr) << file_->GetPath();  
  33. segments_.push_back(segment.release());  
byte* p_vaddr = base_address_ + program_header.p_vaddr;    int prot = 0;    if (executable && ((program_header.p_flags & llvm::ELF::PF_X) != 0)) {      prot |= PROT_EXEC;    }    if ((program_header.p_flags & llvm::ELF::PF_W) != 0) {      prot |= PROT_WRITE;    }    if ((program_header.p_flags & llvm::ELF::PF_R) != 0) {      prot |= PROT_READ;    }    int flags = MAP_FIXED;    if (writable_) {      prot |= PROT_WRITE;      flags |= MAP_SHARED;    } else {      flags |= MAP_PRIVATE;    }    if (file_length < (program_header.p_offset + program_header.p_memsz)) {      LOG(WARNING) << "File size of " << file_length                   << " bytes not large enough to contain ELF segment " << i                   << " of " << (program_header.p_offset + program_header.p_memsz)                   << " bytes: " << file_->GetPath();      return false;    }    UniquePtr
segment(MemMap::MapFileAtAddress(p_vaddr, program_header.p_memsz, prot, flags, file_->Fd(), program_header.p_offset, true)); CHECK(segment.get() != NULL) << file_->GetPath(); CHECK_EQ(segment->Begin(), p_vaddr) << file_->GetPath(); segments_.push_back(segment.release()); }
这下就非常简单了,很容易懂,MemMap::MapFileAtAddress前面分析过。

好,讲了那么多,大致总结一下。

1)如果elf文件中包含了虚拟地址为0的PT_LOAD段,则证明它不是Boot Oat,而是一个普通的应用程序的oat,这时候该elf文件无所谓被映射到内存中的任何地方,其虚拟地址(p_vaddr)中记录的是该段相对于文件头的偏移;

2)如果elf文件中没有包含任何虚拟地址为0的PT_LOAD段,则证明它是一个Boot Oat,必须被加载到一个指定位置(实际是紧接在Image之后),其虚拟地址(p_vaddr)中记录的就是实际要被加载的绝对地址。接下来,ElfFile::Load函数会初始化自己的内部变量,指向各个特殊节的位置:

[cpp]
  1. dynamic_section_start_  
  2.     = reinterpret_cast<llvm::ELF::Elf32_Dyn*>(base_address_ + GetDynamicProgramHeader().p_vaddr);  
  3. for (llvm::ELF::Elf32_Word i = 0; i < GetDynamicNum(); i++) {  
  4.   llvm::ELF::Elf32_Dyn& elf_dyn = GetDynamic(i);  
  5.   byte* d_ptr = base_address_ + elf_dyn.d_un.d_ptr;  
  6.   switch (elf_dyn.d_tag) {  
  7.     case llvm::ELF::DT_HASH: {  
  8.       hash_section_start_ = reinterpret_cast<llvm::ELF::Elf32_Word*>(d_ptr);  
  9.       break;  
  10.     }  
  11.     case llvm::ELF::DT_STRTAB: {  
  12.       dynstr_section_start_ = reinterpret_cast<char*>(d_ptr);  
  13.       break;  
  14.     }  
  15.     case llvm::ELF::DT_SYMTAB: {  
  16.       dynsym_section_start_ = reinterpret_cast<llvm::ELF::Elf32_Sym*>(d_ptr);  
  17.       break;  
  18.     }  
  19.     case llvm::ELF::DT_NULL: {  
  20.       CHECK_EQ(GetDynamicNum(), i+1);  
  21.       break;  
  22.     }  
  23.   }  
  24. }  
  25.   
  26. return true;  
dynamic_section_start_      = reinterpret_cast
(base_address_ + GetDynamicProgramHeader().p_vaddr); for (llvm::ELF::Elf32_Word i = 0; i < GetDynamicNum(); i++) { llvm::ELF::Elf32_Dyn& elf_dyn = GetDynamic(i); byte* d_ptr = base_address_ + elf_dyn.d_un.d_ptr; switch (elf_dyn.d_tag) { case llvm::ELF::DT_HASH: { hash_section_start_ = reinterpret_cast
(d_ptr); break; } case llvm::ELF::DT_STRTAB: { dynstr_section_start_ = reinterpret_cast
(d_ptr); break; } case llvm::ELF::DT_SYMTAB: { dynsym_section_start_ = reinterpret_cast
(d_ptr); break; } case llvm::ELF::DT_NULL: { CHECK_EQ(GetDynamicNum(), i+1); break; } } } return true;}
好了,到现在位置,elf文件已经被完全加载到内存中了,并且所有环境变量都已经初始化完成。那下面要干什么呢?我们接着往下看OatFile::ElfFileOpen:

[cpp]
  1.   begin_ = elf_file_->FindDynamicSymbolAddress("oatdata");  
  2.   if (begin_ == NULL) {  
  3.     LOG(WARNING) << "Failed to find oatdata symbol in " << file->GetPath();  
  4.     return false;  
  5.   }  
  6.   if (requested_base != NULL && begin_ != requested_base) {  
  7.     std::string maps;  
  8.     ReadFileToString("/proc/self/maps", &maps);  
  9.     LOG(WARNING) << "Failed to find oatdata symbol at expected address: oatdata="  
  10.                  << reinterpret_cast<const void*>(begin_) << " != expected="  
  11.                  << reinterpret_cast<const void*>(requested_base)  
  12.                  << " /proc/self/maps:\n" << maps;  
  13.     return false;  
  14.   }  
  15.   end_ = elf_file_->FindDynamicSymbolAddress("oatlastword");  
  16.   if (end_ == NULL) {  
  17.     LOG(WARNING) << "Failed to find oatlastword symbol in " << file->GetPath();  
  18.     return false;  
  19.   }  
  20.   // Readjust to be non-inclusive upper bound.   
  21.   end_ += sizeof(uint32_t);  
  22.   return Setup();  
  23. }  
begin_ = elf_file_->FindDynamicSymbolAddress("oatdata");  if (begin_ == NULL) {    LOG(WARNING) << "Failed to find oatdata symbol in " << file->GetPath();    return false;  }  if (requested_base != NULL && begin_ != requested_base) {    std::string maps;    ReadFileToString("/proc/self/maps", &maps);    LOG(WARNING) << "Failed to find oatdata symbol at expected address: oatdata="                 << reinterpret_cast
(begin_) << " != expected=" << reinterpret_cast
(requested_base) << " /proc/self/maps:\n" << maps; return false; } end_ = elf_file_->FindDynamicSymbolAddress("oatlastword"); if (end_ == NULL) { LOG(WARNING) << "Failed to find oatlastword symbol in " << file->GetPath(); return false; } // Readjust to be non-inclusive upper bound. end_ += sizeof(uint32_t); return Setup();}
看到oatdata和oatlastword了吧,这段代码就是初始化了begin_和end_两个内部变量,分别是oatdata和oatlastword指向的地址。对于前面的Boot Oat文件来说,其值分别为0x60a9d000和0x646161a4。后面还把end_的位置加了4个字节,这是因为oatlastword长度被指定为4个字节,位置又在文件的末尾,必须得加上才真的是指向文件的末尾。那begin_和end_到底被指向了哪里呢?可以通过函数最后调用的ElfFile::Setup函数找出答案。

写了太多了,在下篇我们再接着分析。

你可能感兴趣的文章
mockito 多层调用_连续调用的Mockito迭代器样式存根
查看>>
easymock使用方法_EasyMock静态方法– PowerMock,JUnit 4,TestNG
查看>>
textswitcher_Android TextSwitcher和ImageSwitcher示例教程
查看>>
wordpress评论框_如何通过过滤和阻止它们来抵御WordPress垃圾评论
查看>>
dvm与art的区别_Android运行时– DVM与ART,AOT与JIT
查看>>
ubuntu的web服务器_如何在Ubuntu上安装OpenLiteSpeed Web服务器?
查看>>
java spi_Java SPI(服务提供商接口)和ServiceLoader
查看>>
Java SE 9:使用Eclipse和IntelliJ IDEA IDE开发和测试HelloWorld模块(第4部分)
查看>>
wordpress 自定义_WordPress自定义帖子类型:它是什么以及如何创建?
查看>>
python列重命名_Python目录–创建,重命名,删除,列出,更改
查看>>
在Ubuntu 18.04上使用Postgres,Nginx和Gunicorn设置Django
查看>>
junit5 动态测试_JUnit 5动态测试– @ TestFactory,DynamicTest
查看>>
struts2 拦截器_Struts2 execAndWait拦截器示例,用于长时间运行的动作
查看>>
lshw linux_Linux lshw命令–获取Linux硬件信息
查看>>
primefaces_Primefaces消息,消息和低吼组件示例
查看>>
向下滑动动画android_Android SwipeRefreshLayout – Android向下拉动/向下滑动即可刷新
查看>>
primefaces_Primefaces AccordionPanel组件示例
查看>>
angularjs路由_AngularJS路由示例– ngRoute,$ routeProvider
查看>>
Android ProgressDialog示例
查看>>
jquery 弹出窗口_jQuery弹出窗口和工具提示窗口动画效果
查看>>