diff options
author | Tudor Florea <tudor.florea@enea.com> | 2014-10-16 03:05:19 +0200 |
---|---|---|
committer | Tudor Florea <tudor.florea@enea.com> | 2014-10-16 03:05:19 +0200 |
commit | c527fd1f14c27855a37f2e8ac5346ce8d940ced2 (patch) | |
tree | bb002c1fdf011c41dbd2f0927bed23ecb5f83c97 /scripts/relocate_sdk.py | |
download | poky-c527fd1f14c27855a37f2e8ac5346ce8d940ced2.tar.gz |
initial commit for Enea Linux 4.0-140929daisy-140929
Migrated from the internal git server on the daisy-enea-point-release branch
Signed-off-by: Tudor Florea <tudor.florea@enea.com>
Diffstat (limited to 'scripts/relocate_sdk.py')
-rwxr-xr-x | scripts/relocate_sdk.py | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/scripts/relocate_sdk.py b/scripts/relocate_sdk.py new file mode 100755 index 0000000000..05d9fd65ed --- /dev/null +++ b/scripts/relocate_sdk.py | |||
@@ -0,0 +1,243 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # | ||
3 | # Copyright (c) 2012 Intel Corporation | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License version 2 as | ||
7 | # published by the Free Software Foundation. | ||
8 | # | ||
9 | # This program is distributed in the hope that it will be useful, | ||
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
12 | # See the GNU General Public License for more details. | ||
13 | # | ||
14 | # You should have received a copy of the GNU General Public License | ||
15 | # along with this program; if not, write to the Free Software | ||
16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | # | ||
18 | # DESCRIPTION | ||
19 | # This script is called by the SDK installer script. It replaces the dynamic | ||
20 | # loader path in all binaries and also fixes the SYSDIR paths/lengths and the | ||
21 | # location of ld.so.cache in the dynamic loader binary | ||
22 | # | ||
23 | # AUTHORS | ||
24 | # Laurentiu Palcu <laurentiu.palcu@intel.com> | ||
25 | # | ||
26 | |||
27 | import struct | ||
28 | import sys | ||
29 | import stat | ||
30 | import os | ||
31 | import re | ||
32 | import errno | ||
33 | |||
34 | if sys.version < '3': | ||
35 | def b(x): | ||
36 | return x | ||
37 | else: | ||
38 | def b(x): | ||
39 | return x.encode(sys.getfilesystemencoding()) | ||
40 | |||
41 | old_prefix = re.compile(b("##DEFAULT_INSTALL_DIR##")) | ||
42 | |||
43 | def get_arch(): | ||
44 | f.seek(0) | ||
45 | e_ident =f.read(16) | ||
46 | ei_mag0,ei_mag1_3,ei_class = struct.unpack("<B3sB11x", e_ident) | ||
47 | |||
48 | if (ei_mag0 != 0x7f and ei_mag1_3 != "ELF") or ei_class == 0: | ||
49 | return 0 | ||
50 | |||
51 | if ei_class == 1: | ||
52 | return 32 | ||
53 | elif ei_class == 2: | ||
54 | return 64 | ||
55 | |||
56 | def parse_elf_header(): | ||
57 | global e_type, e_machine, e_version, e_entry, e_phoff, e_shoff, e_flags,\ | ||
58 | e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, e_shstrndx | ||
59 | |||
60 | f.seek(0) | ||
61 | elf_header = f.read(64) | ||
62 | |||
63 | if arch == 32: | ||
64 | # 32bit | ||
65 | hdr_fmt = "<HHILLLIHHHHHH" | ||
66 | hdr_size = 52 | ||
67 | else: | ||
68 | # 64bit | ||
69 | hdr_fmt = "<HHIQQQIHHHHHH" | ||
70 | hdr_size = 64 | ||
71 | |||
72 | e_type, e_machine, e_version, e_entry, e_phoff, e_shoff, e_flags,\ | ||
73 | e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, e_shstrndx =\ | ||
74 | struct.unpack(hdr_fmt, elf_header[16:hdr_size]) | ||
75 | |||
76 | def change_interpreter(elf_file_name): | ||
77 | if arch == 32: | ||
78 | ph_fmt = "<IIIIIIII" | ||
79 | else: | ||
80 | ph_fmt = "<IIQQQQQQ" | ||
81 | |||
82 | """ look for PT_INTERP section """ | ||
83 | for i in range(0,e_phnum): | ||
84 | f.seek(e_phoff + i * e_phentsize) | ||
85 | ph_hdr = f.read(e_phentsize) | ||
86 | if arch == 32: | ||
87 | # 32bit | ||
88 | p_type, p_offset, p_vaddr, p_paddr, p_filesz,\ | ||
89 | p_memsz, p_flags, p_align = struct.unpack(ph_fmt, ph_hdr) | ||
90 | else: | ||
91 | # 64bit | ||
92 | p_type, p_flags, p_offset, p_vaddr, p_paddr, \ | ||
93 | p_filesz, p_memsz, p_align = struct.unpack(ph_fmt, ph_hdr) | ||
94 | |||
95 | """ change interpreter """ | ||
96 | if p_type == 3: | ||
97 | # PT_INTERP section | ||
98 | f.seek(p_offset) | ||
99 | # External SDKs with mixed pre-compiled binaries should not get | ||
100 | # relocated so look for some variant of /lib | ||
101 | fname = f.read(11) | ||
102 | if fname.startswith(b("/lib/")) or fname.startswith(b("/lib64/")) or \ | ||
103 | fname.startswith(b("/lib32/")) or fname.startswith(b("/usr/lib32/")) or \ | ||
104 | fname.startswith(b("/usr/lib32/")) or fname.startswith(b("/usr/lib64/")): | ||
105 | break | ||
106 | if (len(new_dl_path) >= p_filesz): | ||
107 | print("ERROR: could not relocate %s, interp size = %i and %i is needed." \ | ||
108 | % (elf_file_name, p_memsz, len(new_dl_path) + 1)) | ||
109 | break | ||
110 | dl_path = new_dl_path + b("\0") * (p_filesz - len(new_dl_path)) | ||
111 | f.seek(p_offset) | ||
112 | f.write(dl_path) | ||
113 | break | ||
114 | |||
115 | def change_dl_sysdirs(): | ||
116 | if arch == 32: | ||
117 | sh_fmt = "<IIIIIIIIII" | ||
118 | else: | ||
119 | sh_fmt = "<IIQQQQIIQQ" | ||
120 | |||
121 | """ read section string table """ | ||
122 | f.seek(e_shoff + e_shstrndx * e_shentsize) | ||
123 | sh_hdr = f.read(e_shentsize) | ||
124 | if arch == 32: | ||
125 | sh_offset, sh_size = struct.unpack("<16xII16x", sh_hdr) | ||
126 | else: | ||
127 | sh_offset, sh_size = struct.unpack("<24xQQ24x", sh_hdr) | ||
128 | |||
129 | f.seek(sh_offset) | ||
130 | sh_strtab = f.read(sh_size) | ||
131 | |||
132 | sysdirs = sysdirs_len = "" | ||
133 | |||
134 | """ change ld.so.cache path and default libs path for dynamic loader """ | ||
135 | for i in range(0,e_shnum): | ||
136 | f.seek(e_shoff + i * e_shentsize) | ||
137 | sh_hdr = f.read(e_shentsize) | ||
138 | |||
139 | sh_name, sh_type, sh_flags, sh_addr, sh_offset, sh_size, sh_link,\ | ||
140 | sh_info, sh_addralign, sh_entsize = struct.unpack(sh_fmt, sh_hdr) | ||
141 | |||
142 | name = sh_strtab[sh_name:sh_strtab.find(b("\0"), sh_name)] | ||
143 | |||
144 | """ look only into SHT_PROGBITS sections """ | ||
145 | if sh_type == 1: | ||
146 | f.seek(sh_offset) | ||
147 | """ default library paths cannot be changed on the fly because """ | ||
148 | """ the string lengths have to be changed too. """ | ||
149 | if name == b(".sysdirs"): | ||
150 | sysdirs = f.read(sh_size) | ||
151 | sysdirs_off = sh_offset | ||
152 | sysdirs_sect_size = sh_size | ||
153 | elif name == b(".sysdirslen"): | ||
154 | sysdirslen = f.read(sh_size) | ||
155 | sysdirslen_off = sh_offset | ||
156 | elif name == b(".ldsocache"): | ||
157 | ldsocache_path = f.read(sh_size) | ||
158 | new_ldsocache_path = old_prefix.sub(new_prefix, ldsocache_path) | ||
159 | # pad with zeros | ||
160 | new_ldsocache_path += b("\0") * (sh_size - len(new_ldsocache_path)) | ||
161 | # write it back | ||
162 | f.seek(sh_offset) | ||
163 | f.write(new_ldsocache_path) | ||
164 | |||
165 | if sysdirs != "" and sysdirslen != "": | ||
166 | paths = sysdirs.split(b("\0")) | ||
167 | sysdirs = b("") | ||
168 | sysdirslen = b("") | ||
169 | for path in paths: | ||
170 | """ exit the loop when we encounter first empty string """ | ||
171 | if path == b(""): | ||
172 | break | ||
173 | |||
174 | new_path = old_prefix.sub(new_prefix, path) | ||
175 | sysdirs += new_path + b("\0") | ||
176 | |||
177 | if arch == 32: | ||
178 | sysdirslen += struct.pack("<L", len(new_path)) | ||
179 | else: | ||
180 | sysdirslen += struct.pack("<Q", len(new_path)) | ||
181 | |||
182 | """ pad with zeros """ | ||
183 | sysdirs += b("\0") * (sysdirs_sect_size - len(sysdirs)) | ||
184 | |||
185 | """ write the sections back """ | ||
186 | f.seek(sysdirs_off) | ||
187 | f.write(sysdirs) | ||
188 | f.seek(sysdirslen_off) | ||
189 | f.write(sysdirslen) | ||
190 | |||
191 | # MAIN | ||
192 | if len(sys.argv) < 4: | ||
193 | sys.exit(-1) | ||
194 | |||
195 | # In python > 3, strings may also contain Unicode characters. So, convert | ||
196 | # them to bytes | ||
197 | if sys.version_info < (3,): | ||
198 | new_prefix = sys.argv[1] | ||
199 | new_dl_path = sys.argv[2] | ||
200 | else: | ||
201 | new_prefix = sys.argv[1].encode() | ||
202 | new_dl_path = sys.argv[2].encode() | ||
203 | |||
204 | executables_list = sys.argv[3:] | ||
205 | |||
206 | for e in executables_list: | ||
207 | perms = os.stat(e)[stat.ST_MODE] | ||
208 | if os.access(e, os.W_OK|os.R_OK): | ||
209 | perms = None | ||
210 | else: | ||
211 | os.chmod(e, perms|stat.S_IRWXU) | ||
212 | |||
213 | try: | ||
214 | f = open(e, "r+b") | ||
215 | except IOError: | ||
216 | exctype, ioex = sys.exc_info()[:2] | ||
217 | if ioex.errno == errno.ETXTBSY: | ||
218 | print("Could not open %s. File used by another process.\nPlease "\ | ||
219 | "make sure you exit all processes that might use any SDK "\ | ||
220 | "binaries." % e) | ||
221 | else: | ||
222 | print("Could not open %s: %s(%d)" % (e, ioex.strerror, ioex.errno)) | ||
223 | sys.exit(-1) | ||
224 | |||
225 | # Save old size and do a size check at the end. Just a safety measure. | ||
226 | old_size = os.path.getsize(e) | ||
227 | |||
228 | arch = get_arch() | ||
229 | if arch: | ||
230 | parse_elf_header() | ||
231 | change_interpreter(e) | ||
232 | change_dl_sysdirs() | ||
233 | |||
234 | """ change permissions back """ | ||
235 | if perms: | ||
236 | os.chmod(e, perms) | ||
237 | |||
238 | f.close() | ||
239 | |||
240 | if old_size != os.path.getsize(e): | ||
241 | print("New file size for %s is different. Looks like a relocation error!", e) | ||
242 | sys.exit(-1) | ||
243 | |||