1*387f9dfdSAndroid Build Coastguard Worker--[[ 2*387f9dfdSAndroid Build Coastguard WorkerCopyright 2016 Marek Vavrusa <[email protected]> 3*387f9dfdSAndroid Build Coastguard Worker 4*387f9dfdSAndroid Build Coastguard WorkerLicensed under the Apache License, Version 2.0 (the "License"); 5*387f9dfdSAndroid Build Coastguard Workeryou may not use this file except in compliance with the License. 6*387f9dfdSAndroid Build Coastguard WorkerYou may obtain a copy of the License at 7*387f9dfdSAndroid Build Coastguard Worker 8*387f9dfdSAndroid Build Coastguard Workerhttp://www.apache.org/licenses/LICENSE-2.0 9*387f9dfdSAndroid Build Coastguard Worker 10*387f9dfdSAndroid Build Coastguard WorkerUnless required by applicable law or agreed to in writing, software 11*387f9dfdSAndroid Build Coastguard Workerdistributed under the License is distributed on an "AS IS" BASIS, 12*387f9dfdSAndroid Build Coastguard WorkerWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*387f9dfdSAndroid Build Coastguard WorkerSee the License for the specific language governing permissions and 14*387f9dfdSAndroid Build Coastguard Workerlimitations under the License. 15*387f9dfdSAndroid Build Coastguard Worker]] 16*387f9dfdSAndroid Build Coastguard Worker-- This is a tiny wrapper over libelf to extract load address 17*387f9dfdSAndroid Build Coastguard Worker-- and offsets of dynamic symbols 18*387f9dfdSAndroid Build Coastguard Worker 19*387f9dfdSAndroid Build Coastguard Workerlocal S = require('syscall') 20*387f9dfdSAndroid Build Coastguard Workerlocal ffi = require('ffi') 21*387f9dfdSAndroid Build Coastguard Workerffi.cdef [[ 22*387f9dfdSAndroid Build Coastguard Worker/* Type for a 16-bit quantity. */ 23*387f9dfdSAndroid Build Coastguard Workertypedef uint16_t Elf32_Half; 24*387f9dfdSAndroid Build Coastguard Workertypedef uint16_t Elf64_Half; 25*387f9dfdSAndroid Build Coastguard Worker 26*387f9dfdSAndroid Build Coastguard Worker/* Types for signed and unsigned 32-bit quantities. */ 27*387f9dfdSAndroid Build Coastguard Workertypedef uint32_t Elf32_Word; 28*387f9dfdSAndroid Build Coastguard Workertypedef int32_t Elf32_Sword; 29*387f9dfdSAndroid Build Coastguard Workertypedef uint32_t Elf64_Word; 30*387f9dfdSAndroid Build Coastguard Workertypedef int32_t Elf64_Sword; 31*387f9dfdSAndroid Build Coastguard Worker 32*387f9dfdSAndroid Build Coastguard Worker/* Types for signed and unsigned 64-bit quantities. */ 33*387f9dfdSAndroid Build Coastguard Workertypedef uint64_t Elf32_Xword; 34*387f9dfdSAndroid Build Coastguard Workertypedef int64_t Elf32_Sxword; 35*387f9dfdSAndroid Build Coastguard Workertypedef uint64_t Elf64_Xword; 36*387f9dfdSAndroid Build Coastguard Workertypedef int64_t Elf64_Sxword; 37*387f9dfdSAndroid Build Coastguard Worker 38*387f9dfdSAndroid Build Coastguard Worker/* Type of addresses. */ 39*387f9dfdSAndroid Build Coastguard Workertypedef uint32_t Elf32_Addr; 40*387f9dfdSAndroid Build Coastguard Workertypedef uint64_t Elf64_Addr; 41*387f9dfdSAndroid Build Coastguard Worker 42*387f9dfdSAndroid Build Coastguard Worker/* Type of file offsets. */ 43*387f9dfdSAndroid Build Coastguard Workertypedef uint32_t Elf32_Off; 44*387f9dfdSAndroid Build Coastguard Workertypedef uint64_t Elf64_Off; 45*387f9dfdSAndroid Build Coastguard Worker 46*387f9dfdSAndroid Build Coastguard Worker/* Type for section indices, which are 16-bit quantities. */ 47*387f9dfdSAndroid Build Coastguard Workertypedef uint16_t Elf32_Section; 48*387f9dfdSAndroid Build Coastguard Workertypedef uint16_t Elf64_Section; 49*387f9dfdSAndroid Build Coastguard Worker 50*387f9dfdSAndroid Build Coastguard Worker/* Constants */ 51*387f9dfdSAndroid Build Coastguard Workerstruct Elf_Cmd 52*387f9dfdSAndroid Build Coastguard Worker{ 53*387f9dfdSAndroid Build Coastguard Worker static const int READ = 1; 54*387f9dfdSAndroid Build Coastguard Worker static const int RDWR = 2; 55*387f9dfdSAndroid Build Coastguard Worker static const int WRITE = 3; 56*387f9dfdSAndroid Build Coastguard Worker static const int CLR = 4; 57*387f9dfdSAndroid Build Coastguard Worker static const int SET = 5; 58*387f9dfdSAndroid Build Coastguard Worker static const int FDDONE = 6; 59*387f9dfdSAndroid Build Coastguard Worker static const int FDREAD = 7; 60*387f9dfdSAndroid Build Coastguard Worker static const int READ_MMAP = 8; 61*387f9dfdSAndroid Build Coastguard Worker static const int RDWR_MMAP = 9; 62*387f9dfdSAndroid Build Coastguard Worker static const int WRITE_MMAP =10; 63*387f9dfdSAndroid Build Coastguard Worker static const int READ_MMAP_PRIVATE =11; 64*387f9dfdSAndroid Build Coastguard Worker static const int EMPTY =12; 65*387f9dfdSAndroid Build Coastguard Worker static const int NUM =13; 66*387f9dfdSAndroid Build Coastguard Worker}; 67*387f9dfdSAndroid Build Coastguard Worker 68*387f9dfdSAndroid Build Coastguard Worker/* Descriptor for the ELF file. */ 69*387f9dfdSAndroid Build Coastguard Workertypedef struct Elf Elf; 70*387f9dfdSAndroid Build Coastguard Worker/* Descriptor for ELF file section. */ 71*387f9dfdSAndroid Build Coastguard Workertypedef struct Elf_Scn Elf_Scn; 72*387f9dfdSAndroid Build Coastguard Worker/* Container type for metatable */ 73*387f9dfdSAndroid Build Coastguard Workerstruct Elf_object { int fd; Elf *elf; }; 74*387f9dfdSAndroid Build Coastguard Worker/* Program segment header. */ 75*387f9dfdSAndroid Build Coastguard Workertypedef struct 76*387f9dfdSAndroid Build Coastguard Worker{ 77*387f9dfdSAndroid Build Coastguard Worker Elf64_Word p_type; /* Segment type */ 78*387f9dfdSAndroid Build Coastguard Worker Elf64_Word p_flags; /* Segment flags */ 79*387f9dfdSAndroid Build Coastguard Worker Elf64_Off p_offset; /* Segment file offset */ 80*387f9dfdSAndroid Build Coastguard Worker Elf64_Addr p_vaddr; /* Segment virtual address */ 81*387f9dfdSAndroid Build Coastguard Worker Elf64_Addr p_paddr; /* Segment physical address */ 82*387f9dfdSAndroid Build Coastguard Worker Elf64_Xword p_filesz; /* Segment size in file */ 83*387f9dfdSAndroid Build Coastguard Worker Elf64_Xword p_memsz; /* Segment size in memory */ 84*387f9dfdSAndroid Build Coastguard Worker Elf64_Xword p_align; /* Segment alignment */ 85*387f9dfdSAndroid Build Coastguard Worker} Elf64_Phdr; 86*387f9dfdSAndroid Build Coastguard Workertypedef Elf64_Phdr GElf_Phdr; 87*387f9dfdSAndroid Build Coastguard Worker/* Section header. */ 88*387f9dfdSAndroid Build Coastguard Workertypedef struct 89*387f9dfdSAndroid Build Coastguard Worker{ 90*387f9dfdSAndroid Build Coastguard Worker Elf64_Word sh_name; /* Section name (string tbl index) */ 91*387f9dfdSAndroid Build Coastguard Worker Elf64_Word sh_type; /* Section type */ 92*387f9dfdSAndroid Build Coastguard Worker Elf64_Xword sh_flags; /* Section flags */ 93*387f9dfdSAndroid Build Coastguard Worker Elf64_Addr sh_addr; /* Section virtual addr at execution */ 94*387f9dfdSAndroid Build Coastguard Worker Elf64_Off sh_offset; /* Section file offset */ 95*387f9dfdSAndroid Build Coastguard Worker Elf64_Xword sh_size; /* Section size in bytes */ 96*387f9dfdSAndroid Build Coastguard Worker Elf64_Word sh_link; /* Link to another section */ 97*387f9dfdSAndroid Build Coastguard Worker Elf64_Word sh_info; /* Additional section information */ 98*387f9dfdSAndroid Build Coastguard Worker Elf64_Xword sh_addralign; /* Section alignment */ 99*387f9dfdSAndroid Build Coastguard Worker Elf64_Xword sh_entsize; /* Entry size if section holds table */ 100*387f9dfdSAndroid Build Coastguard Worker} Elf64_Shdr; 101*387f9dfdSAndroid Build Coastguard Workertypedef Elf64_Shdr GElf_Shdr; 102*387f9dfdSAndroid Build Coastguard Worker/* Descriptor for data to be converted to or from memory format. */ 103*387f9dfdSAndroid Build Coastguard Workertypedef struct 104*387f9dfdSAndroid Build Coastguard Worker{ 105*387f9dfdSAndroid Build Coastguard Worker void *d_buf; /* Pointer to the actual data. */ 106*387f9dfdSAndroid Build Coastguard Worker int d_type; /* Type of this piece of data. */ 107*387f9dfdSAndroid Build Coastguard Worker unsigned int d_version; /* ELF version. */ 108*387f9dfdSAndroid Build Coastguard Worker size_t d_size; /* Size in bytes. */ 109*387f9dfdSAndroid Build Coastguard Worker uint64_t d_off; /* Offset into section. */ 110*387f9dfdSAndroid Build Coastguard Worker size_t d_align; /* Alignment in section. */ 111*387f9dfdSAndroid Build Coastguard Worker} Elf_Data; 112*387f9dfdSAndroid Build Coastguard Worker/* Symbol table entry. */ 113*387f9dfdSAndroid Build Coastguard Workertypedef struct 114*387f9dfdSAndroid Build Coastguard Worker{ 115*387f9dfdSAndroid Build Coastguard Worker Elf64_Word st_name; /* Symbol name (string tbl index) */ 116*387f9dfdSAndroid Build Coastguard Worker unsigned char st_info; /* Symbol type and binding */ 117*387f9dfdSAndroid Build Coastguard Worker unsigned char st_other; /* Symbol visibility */ 118*387f9dfdSAndroid Build Coastguard Worker Elf64_Section st_shndx; /* Section index */ 119*387f9dfdSAndroid Build Coastguard Worker Elf64_Addr st_value; /* Symbol value */ 120*387f9dfdSAndroid Build Coastguard Worker Elf64_Xword st_size; /* Symbol size */ 121*387f9dfdSAndroid Build Coastguard Worker} Elf64_Sym; 122*387f9dfdSAndroid Build Coastguard Workertypedef Elf64_Sym GElf_Sym; 123*387f9dfdSAndroid Build Coastguard Worker 124*387f9dfdSAndroid Build Coastguard Worker/* Coordinate ELF library and application versions. */ 125*387f9dfdSAndroid Build Coastguard Workerunsigned int elf_version (unsigned int __version); 126*387f9dfdSAndroid Build Coastguard Worker/* Return descriptor for ELF file to work according to CMD. */ 127*387f9dfdSAndroid Build Coastguard WorkerElf *elf_begin (int __fildes, int __cmd, Elf *__ref); 128*387f9dfdSAndroid Build Coastguard Worker/* Free resources allocated for ELF. */ 129*387f9dfdSAndroid Build Coastguard Workerint elf_end (Elf *__elf); 130*387f9dfdSAndroid Build Coastguard Worker/* Get the number of program headers in the ELF file. If the file uses 131*387f9dfdSAndroid Build Coastguard Worker more headers than can be represented in the e_phnum field of the ELF 132*387f9dfdSAndroid Build Coastguard Worker header the information from the sh_info field in the zeroth section 133*387f9dfdSAndroid Build Coastguard Worker header is used. */ 134*387f9dfdSAndroid Build Coastguard Workerint elf_getphdrnum (Elf *__elf, size_t *__dst); 135*387f9dfdSAndroid Build Coastguard Worker/* Retrieve program header table entry. */ 136*387f9dfdSAndroid Build Coastguard WorkerGElf_Phdr *gelf_getphdr (Elf *__elf, int __ndx, GElf_Phdr *__dst); 137*387f9dfdSAndroid Build Coastguard Worker/* Retrieve section header. */ 138*387f9dfdSAndroid Build Coastguard WorkerGElf_Shdr *gelf_getshdr (Elf_Scn *__scn, GElf_Shdr *__dst); 139*387f9dfdSAndroid Build Coastguard Worker/* Retrieve symbol information from the symbol table at the given index. */ 140*387f9dfdSAndroid Build Coastguard WorkerGElf_Sym *gelf_getsym (Elf_Data *__data, int __ndx, GElf_Sym *__dst); 141*387f9dfdSAndroid Build Coastguard Worker/* Get section with next section index. */ 142*387f9dfdSAndroid Build Coastguard WorkerElf_Scn *elf_nextscn (Elf *__elf, Elf_Scn *__scn); 143*387f9dfdSAndroid Build Coastguard Worker/* Get data from section while translating from file representation 144*387f9dfdSAndroid Build Coastguard Worker to memory representation. */ 145*387f9dfdSAndroid Build Coastguard WorkerElf_Data *elf_getdata (Elf_Scn *__scn, Elf_Data *__data); 146*387f9dfdSAndroid Build Coastguard Worker/* Return pointer to string at OFFSET in section INDEX. */ 147*387f9dfdSAndroid Build Coastguard Workerchar *elf_strptr (Elf *__elf, size_t __index, size_t __offset); 148*387f9dfdSAndroid Build Coastguard Worker]] 149*387f9dfdSAndroid Build Coastguard Worker 150*387f9dfdSAndroid Build Coastguard Workerlocal elf = ffi.load('elf') 151*387f9dfdSAndroid Build Coastguard Workerlocal EV = { NONE=0, CURRENT=1, NUM=2 } 152*387f9dfdSAndroid Build Coastguard Workerlocal PT = { NULL=0, LOAD=1, DYNAMIC=2, INTERP=3, NOTE=4, SHLIB=5, PHDR=6, TLS=7, NUM=8 } 153*387f9dfdSAndroid Build Coastguard Workerlocal SHT = { NULL=0, PROGBITS=1, SYMTAB=2, STRTAB=3, RELA=4, HASH=5, DYNAMIC=6, NOTE=7, 154*387f9dfdSAndroid Build Coastguard Worker NOBITS=8, REL=9, SHLIB=10, DYNSYM=11, INIT_ARRAY=14, FINI_ARRAY=15, PREINIT_ARRAY=16, 155*387f9dfdSAndroid Build Coastguard Worker GROUP=17, SYMTAB_SHNDX=18, NUM=19 } 156*387f9dfdSAndroid Build Coastguard Workerlocal ELF_C = ffi.new('struct Elf_Cmd') 157*387f9dfdSAndroid Build Coastguard Workerlocal M = {} 158*387f9dfdSAndroid Build Coastguard Worker 159*387f9dfdSAndroid Build Coastguard Worker-- Optional poor man's C++ demangler 160*387f9dfdSAndroid Build Coastguard Workerlocal cpp_demangler = os.getenv('CPP_DEMANGLER') 161*387f9dfdSAndroid Build Coastguard Workerif not cpp_demangler then 162*387f9dfdSAndroid Build Coastguard Worker for prefix in string.gmatch(os.getenv('PATH'), '[^;:]+') do 163*387f9dfdSAndroid Build Coastguard Worker if S.statfs(prefix..'/c++filt') then 164*387f9dfdSAndroid Build Coastguard Worker cpp_demangler = prefix..'/c++filt' 165*387f9dfdSAndroid Build Coastguard Worker break 166*387f9dfdSAndroid Build Coastguard Worker end 167*387f9dfdSAndroid Build Coastguard Worker end 168*387f9dfdSAndroid Build Coastguard Workerend 169*387f9dfdSAndroid Build Coastguard Workerlocal cpp_demangle = function (name) return name end 170*387f9dfdSAndroid Build Coastguard Workerif cpp_demangler then 171*387f9dfdSAndroid Build Coastguard Worker cpp_demangle = function (name) 172*387f9dfdSAndroid Build Coastguard Worker local cmd = string.format('%s -p %s', cpp_demangler, name) 173*387f9dfdSAndroid Build Coastguard Worker local fp = assert(io.popen(cmd, 'r')) 174*387f9dfdSAndroid Build Coastguard Worker local output = fp:read('*all') 175*387f9dfdSAndroid Build Coastguard Worker fp:close() 176*387f9dfdSAndroid Build Coastguard Worker return output:match '^(.-)%s*$' 177*387f9dfdSAndroid Build Coastguard Worker end 178*387f9dfdSAndroid Build Coastguard Workerend 179*387f9dfdSAndroid Build Coastguard Worker 180*387f9dfdSAndroid Build Coastguard Worker-- Metatable for ELF object 181*387f9dfdSAndroid Build Coastguard Workerffi.metatype('struct Elf_object', { 182*387f9dfdSAndroid Build Coastguard Worker __gc = function (t) t:close() end, 183*387f9dfdSAndroid Build Coastguard Worker __index = { 184*387f9dfdSAndroid Build Coastguard Worker close = function (t) 185*387f9dfdSAndroid Build Coastguard Worker if t.elf ~= nil then 186*387f9dfdSAndroid Build Coastguard Worker elf.elf_end(t.elf) 187*387f9dfdSAndroid Build Coastguard Worker S.close(t.fd) 188*387f9dfdSAndroid Build Coastguard Worker t.elf = nil 189*387f9dfdSAndroid Build Coastguard Worker end 190*387f9dfdSAndroid Build Coastguard Worker end, 191*387f9dfdSAndroid Build Coastguard Worker -- Load library load address 192*387f9dfdSAndroid Build Coastguard Worker loadaddr = function(t) 193*387f9dfdSAndroid Build Coastguard Worker local phnum = ffi.new('size_t [1]') 194*387f9dfdSAndroid Build Coastguard Worker if elf.elf_getphdrnum(t.elf, phnum) == nil then 195*387f9dfdSAndroid Build Coastguard Worker return nil, 'cannot get phdrnum' 196*387f9dfdSAndroid Build Coastguard Worker end 197*387f9dfdSAndroid Build Coastguard Worker local header = ffi.new('GElf_Phdr [1]') 198*387f9dfdSAndroid Build Coastguard Worker for i = 0, tonumber(phnum[0])-1 do 199*387f9dfdSAndroid Build Coastguard Worker if elf.gelf_getphdr(t.elf, i, header) ~= nil 200*387f9dfdSAndroid Build Coastguard Worker and header[0].p_type == PT.LOAD then 201*387f9dfdSAndroid Build Coastguard Worker return header[0].p_vaddr 202*387f9dfdSAndroid Build Coastguard Worker end 203*387f9dfdSAndroid Build Coastguard Worker end 204*387f9dfdSAndroid Build Coastguard Worker end, 205*387f9dfdSAndroid Build Coastguard Worker -- Resolve symbol address 206*387f9dfdSAndroid Build Coastguard Worker resolve = function (t, k, pattern) 207*387f9dfdSAndroid Build Coastguard Worker local section = elf.elf_nextscn(t.elf, nil) 208*387f9dfdSAndroid Build Coastguard Worker while section ~= nil do 209*387f9dfdSAndroid Build Coastguard Worker local header = ffi.new('GElf_Shdr [1]') 210*387f9dfdSAndroid Build Coastguard Worker if elf.gelf_getshdr(section, header) ~= nil then 211*387f9dfdSAndroid Build Coastguard Worker if header[0].sh_type == SHT.SYMTAB or header[0].sh_type == SHT.DYNSYM then 212*387f9dfdSAndroid Build Coastguard Worker local data = elf.elf_getdata(section, nil) 213*387f9dfdSAndroid Build Coastguard Worker while data ~= nil do 214*387f9dfdSAndroid Build Coastguard Worker if data.d_size % header[0].sh_entsize > 0 then 215*387f9dfdSAndroid Build Coastguard Worker return nil, 'bad section header entity size' 216*387f9dfdSAndroid Build Coastguard Worker end 217*387f9dfdSAndroid Build Coastguard Worker local symcount = tonumber(data.d_size / header[0].sh_entsize) 218*387f9dfdSAndroid Build Coastguard Worker local sym = ffi.new('GElf_Sym [1]') 219*387f9dfdSAndroid Build Coastguard Worker for i = 0, symcount - 1 do 220*387f9dfdSAndroid Build Coastguard Worker if elf.gelf_getsym(data, i, sym) ~= nil then 221*387f9dfdSAndroid Build Coastguard Worker local name = elf.elf_strptr(t.elf, header[0].sh_link, sym[0].st_name) 222*387f9dfdSAndroid Build Coastguard Worker if name ~= nil then 223*387f9dfdSAndroid Build Coastguard Worker -- Demangle C++ symbols if necessary 224*387f9dfdSAndroid Build Coastguard Worker name = ffi.string(name) 225*387f9dfdSAndroid Build Coastguard Worker if name:sub(1,2) == '_Z' then 226*387f9dfdSAndroid Build Coastguard Worker name = cpp_demangle(name) 227*387f9dfdSAndroid Build Coastguard Worker end 228*387f9dfdSAndroid Build Coastguard Worker -- Match symbol name against pattern 229*387f9dfdSAndroid Build Coastguard Worker if pattern and string.match(name, k) or k == name then 230*387f9dfdSAndroid Build Coastguard Worker return sym[0] 231*387f9dfdSAndroid Build Coastguard Worker end 232*387f9dfdSAndroid Build Coastguard Worker end 233*387f9dfdSAndroid Build Coastguard Worker end 234*387f9dfdSAndroid Build Coastguard Worker end 235*387f9dfdSAndroid Build Coastguard Worker data = elf.elf_getdata(section, data) 236*387f9dfdSAndroid Build Coastguard Worker end 237*387f9dfdSAndroid Build Coastguard Worker end 238*387f9dfdSAndroid Build Coastguard Worker end 239*387f9dfdSAndroid Build Coastguard Worker section = elf.elf_nextscn(t.elf, section) 240*387f9dfdSAndroid Build Coastguard Worker end 241*387f9dfdSAndroid Build Coastguard Worker end, 242*387f9dfdSAndroid Build Coastguard Worker } 243*387f9dfdSAndroid Build Coastguard Worker}) 244*387f9dfdSAndroid Build Coastguard Worker 245*387f9dfdSAndroid Build Coastguard Worker-- Open an ELF object 246*387f9dfdSAndroid Build Coastguard Workerfunction M.open(path) 247*387f9dfdSAndroid Build Coastguard Worker if elf.elf_version(EV.CURRENT) == EV.NONE then 248*387f9dfdSAndroid Build Coastguard Worker return nil, 'bad version' 249*387f9dfdSAndroid Build Coastguard Worker end 250*387f9dfdSAndroid Build Coastguard Worker local fd, err = S.open(path, 'rdonly') 251*387f9dfdSAndroid Build Coastguard Worker if not fd then return nil, err end 252*387f9dfdSAndroid Build Coastguard Worker local pt = ffi.new('Elf *') 253*387f9dfdSAndroid Build Coastguard Worker pt = elf.elf_begin(fd:getfd(), ELF_C.READ, pt) 254*387f9dfdSAndroid Build Coastguard Worker if not pt then 255*387f9dfdSAndroid Build Coastguard Worker fd:close() 256*387f9dfdSAndroid Build Coastguard Worker return nil, 'cannot open elf object' 257*387f9dfdSAndroid Build Coastguard Worker end 258*387f9dfdSAndroid Build Coastguard Worker return ffi.new('struct Elf_object', fd:nogc():getfd(), pt) 259*387f9dfdSAndroid Build Coastguard Workerend 260*387f9dfdSAndroid Build Coastguard Worker 261*387f9dfdSAndroid Build Coastguard Workerreturn M