xref: /aosp_15_r20/external/bcc/src/lua/bpf/elf.lua (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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