diff options
Diffstat (limited to 'scripts/relocate_sdk.py')
| -rwxr-xr-x | scripts/relocate_sdk.py | 298 |
1 files changed, 0 insertions, 298 deletions
diff --git a/scripts/relocate_sdk.py b/scripts/relocate_sdk.py deleted file mode 100755 index 9e01c09cb0..0000000000 --- a/scripts/relocate_sdk.py +++ /dev/null | |||
| @@ -1,298 +0,0 @@ | |||
| 1 | #!/usr/bin/env python3 | ||
| 2 | # | ||
| 3 | # Copyright (c) 2012 Intel Corporation | ||
| 4 | # | ||
| 5 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 6 | # | ||
| 7 | # DESCRIPTION | ||
| 8 | # This script is called by the SDK installer script. It replaces the dynamic | ||
| 9 | # loader path in all binaries and also fixes the SYSDIR paths/lengths and the | ||
| 10 | # location of ld.so.cache in the dynamic loader binary | ||
| 11 | # | ||
| 12 | # AUTHORS | ||
| 13 | # Laurentiu Palcu <laurentiu.palcu@intel.com> | ||
| 14 | # | ||
| 15 | |||
| 16 | import struct | ||
| 17 | import sys | ||
| 18 | import stat | ||
| 19 | import os | ||
| 20 | import re | ||
| 21 | import errno | ||
| 22 | |||
| 23 | if sys.version < '3': | ||
| 24 | def b(x): | ||
| 25 | return x | ||
| 26 | else: | ||
| 27 | def b(x): | ||
| 28 | return x.encode(sys.getfilesystemencoding()) | ||
| 29 | |||
| 30 | old_prefix = re.compile(b("##DEFAULT_INSTALL_DIR##")) | ||
| 31 | |||
| 32 | def get_arch(): | ||
| 33 | global endian_prefix | ||
| 34 | f.seek(0) | ||
| 35 | e_ident =f.read(16) | ||
| 36 | ei_mag0,ei_mag1_3,ei_class,ei_data,ei_version = struct.unpack("<B3sBBB9x", e_ident) | ||
| 37 | |||
| 38 | # ei_data = 1 for little-endian & 0 for big-endian | ||
| 39 | if ei_data == 1: | ||
| 40 | endian_prefix = '<' | ||
| 41 | else: | ||
| 42 | endian_prefix = '>' | ||
| 43 | |||
| 44 | if (ei_mag0 != 0x7f and ei_mag1_3 != "ELF") or ei_class == 0: | ||
| 45 | return 0 | ||
| 46 | |||
| 47 | if ei_class == 1: | ||
| 48 | return 32 | ||
| 49 | elif ei_class == 2: | ||
| 50 | return 64 | ||
| 51 | |||
| 52 | def get_dl_arch(dl_path): | ||
| 53 | try: | ||
| 54 | with open(dl_path, "r+b") as f: | ||
| 55 | e_ident =f.read(16) | ||
| 56 | except IOError: | ||
| 57 | exctype, ioex = sys.exc_info()[:2] | ||
| 58 | if ioex.errno == errno.ETXTBSY: | ||
| 59 | print("Could not open %s. File used by another process.\nPlease "\ | ||
| 60 | "make sure you exit all processes that might use any SDK "\ | ||
| 61 | "binaries." % e) | ||
| 62 | else: | ||
| 63 | print("Could not open %s: %s(%d)" % (e, ioex.strerror, ioex.errno)) | ||
| 64 | sys.exit(-1) | ||
| 65 | |||
| 66 | ei_mag0,ei_mag1_3,ei_class,ei_data,ei_version = struct.unpack("<B3sBBB9x", e_ident) | ||
| 67 | |||
| 68 | if (ei_mag0 != 0x7f and ei_mag1_3 != "ELF") or ei_class == 0: | ||
| 69 | print("ERROR: unknow %s" % dl_path) | ||
| 70 | sys.exit(-1) | ||
| 71 | |||
| 72 | if ei_class == 1: | ||
| 73 | arch = 32 | ||
| 74 | elif ei_class == 2: | ||
| 75 | arch = 64 | ||
| 76 | |||
| 77 | return arch | ||
| 78 | |||
| 79 | |||
| 80 | def parse_elf_header(): | ||
| 81 | global e_type, e_machine, e_version, e_entry, e_phoff, e_shoff, e_flags,\ | ||
| 82 | e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, e_shstrndx | ||
| 83 | |||
| 84 | f.seek(0) | ||
| 85 | elf_header = f.read(64) | ||
| 86 | |||
| 87 | if arch == 32: | ||
| 88 | # 32bit | ||
| 89 | hdr_fmt = endian_prefix + "HHILLLIHHHHHH" | ||
| 90 | hdr_size = 52 | ||
| 91 | else: | ||
| 92 | # 64bit | ||
| 93 | hdr_fmt = endian_prefix + "HHIQQQIHHHHHH" | ||
| 94 | hdr_size = 64 | ||
| 95 | |||
| 96 | e_type, e_machine, e_version, e_entry, e_phoff, e_shoff, e_flags,\ | ||
| 97 | e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, e_shstrndx =\ | ||
| 98 | struct.unpack(hdr_fmt, elf_header[16:hdr_size]) | ||
| 99 | |||
| 100 | def change_interpreter(elf_file_name): | ||
| 101 | if arch == 32: | ||
| 102 | ph_fmt = endian_prefix + "IIIIIIII" | ||
| 103 | else: | ||
| 104 | ph_fmt = endian_prefix + "IIQQQQQQ" | ||
| 105 | |||
| 106 | """ look for PT_INTERP section """ | ||
| 107 | for i in range(0,e_phnum): | ||
| 108 | f.seek(e_phoff + i * e_phentsize) | ||
| 109 | ph_hdr = f.read(e_phentsize) | ||
| 110 | if arch == 32: | ||
| 111 | # 32bit | ||
| 112 | p_type, p_offset, p_vaddr, p_paddr, p_filesz,\ | ||
| 113 | p_memsz, p_flags, p_align = struct.unpack(ph_fmt, ph_hdr) | ||
| 114 | else: | ||
| 115 | # 64bit | ||
| 116 | p_type, p_flags, p_offset, p_vaddr, p_paddr, \ | ||
| 117 | p_filesz, p_memsz, p_align = struct.unpack(ph_fmt, ph_hdr) | ||
| 118 | |||
| 119 | """ change interpreter """ | ||
| 120 | if p_type == 3: | ||
| 121 | # PT_INTERP section | ||
| 122 | f.seek(p_offset) | ||
| 123 | # External SDKs with mixed pre-compiled binaries should not get | ||
| 124 | # relocated so look for some variant of /lib | ||
| 125 | fname = f.read(11) | ||
| 126 | if fname.startswith(b("/lib/")) or fname.startswith(b("/lib64/")) or \ | ||
| 127 | fname.startswith(b("/lib32/")) or fname.startswith(b("/usr/lib32/")) or \ | ||
| 128 | fname.startswith(b("/usr/lib32/")) or fname.startswith(b("/usr/lib64/")): | ||
| 129 | break | ||
| 130 | if p_filesz == 0: | ||
| 131 | break | ||
| 132 | if (len(new_dl_path) >= p_filesz): | ||
| 133 | print("ERROR: could not relocate %s, interp size = %i and %i is needed." \ | ||
| 134 | % (elf_file_name, p_memsz, len(new_dl_path) + 1)) | ||
| 135 | return False | ||
| 136 | dl_path = new_dl_path + b("\0") * (p_filesz - len(new_dl_path)) | ||
| 137 | f.seek(p_offset) | ||
| 138 | f.write(dl_path) | ||
| 139 | break | ||
| 140 | return True | ||
| 141 | |||
| 142 | def change_dl_sysdirs(elf_file_name): | ||
| 143 | if arch == 32: | ||
| 144 | sh_fmt = endian_prefix + "IIIIIIIIII" | ||
| 145 | else: | ||
| 146 | sh_fmt = endian_prefix + "IIQQQQIIQQ" | ||
| 147 | |||
| 148 | """ read section string table """ | ||
| 149 | f.seek(e_shoff + e_shstrndx * e_shentsize) | ||
| 150 | sh_hdr = f.read(e_shentsize) | ||
| 151 | if arch == 32: | ||
| 152 | sh_offset, sh_size = struct.unpack(endian_prefix + "16xII16x", sh_hdr) | ||
| 153 | else: | ||
| 154 | sh_offset, sh_size = struct.unpack(endian_prefix + "24xQQ24x", sh_hdr) | ||
| 155 | |||
| 156 | f.seek(sh_offset) | ||
| 157 | sh_strtab = f.read(sh_size) | ||
| 158 | |||
| 159 | sysdirs = sysdirs_len = "" | ||
| 160 | |||
| 161 | """ change ld.so.cache path and default libs path for dynamic loader """ | ||
| 162 | for i in range(0,e_shnum): | ||
| 163 | f.seek(e_shoff + i * e_shentsize) | ||
| 164 | sh_hdr = f.read(e_shentsize) | ||
| 165 | |||
| 166 | sh_name, sh_type, sh_flags, sh_addr, sh_offset, sh_size, sh_link,\ | ||
| 167 | sh_info, sh_addralign, sh_entsize = struct.unpack(sh_fmt, sh_hdr) | ||
| 168 | |||
| 169 | name = sh_strtab[sh_name:sh_strtab.find(b("\0"), sh_name)] | ||
| 170 | |||
| 171 | """ look only into SHT_PROGBITS sections """ | ||
| 172 | if sh_type == 1: | ||
| 173 | f.seek(sh_offset) | ||
| 174 | """ default library paths cannot be changed on the fly because """ | ||
| 175 | """ the string lengths have to be changed too. """ | ||
| 176 | if name == b(".sysdirs"): | ||
| 177 | sysdirs = f.read(sh_size) | ||
| 178 | sysdirs_off = sh_offset | ||
| 179 | sysdirs_sect_size = sh_size | ||
| 180 | elif name == b(".sysdirslen"): | ||
| 181 | sysdirslen = f.read(sh_size) | ||
| 182 | sysdirslen_off = sh_offset | ||
| 183 | elif name == b(".ldsocache"): | ||
| 184 | ldsocache_path = f.read(sh_size) | ||
| 185 | new_ldsocache_path = old_prefix.sub(new_prefix, ldsocache_path) | ||
| 186 | new_ldsocache_path = new_ldsocache_path.rstrip(b("\0")) | ||
| 187 | if (len(new_ldsocache_path) >= sh_size): | ||
| 188 | print("ERROR: could not relocate %s, .ldsocache section size = %i and %i is needed." \ | ||
| 189 | % (elf_file_name, sh_size, len(new_ldsocache_path))) | ||
| 190 | sys.exit(-1) | ||
| 191 | # pad with zeros | ||
| 192 | new_ldsocache_path += b("\0") * (sh_size - len(new_ldsocache_path)) | ||
| 193 | # write it back | ||
| 194 | f.seek(sh_offset) | ||
| 195 | f.write(new_ldsocache_path) | ||
| 196 | elif name == b(".gccrelocprefix"): | ||
| 197 | offset = 0 | ||
| 198 | while (offset + 4096) <= sh_size: | ||
| 199 | path = f.read(4096) | ||
| 200 | new_path = old_prefix.sub(new_prefix, path) | ||
| 201 | new_path = new_path.rstrip(b("\0")) | ||
| 202 | if (len(new_path) >= 4096): | ||
| 203 | print("ERROR: could not relocate %s, max path size = 4096 and %i is needed." \ | ||
| 204 | % (elf_file_name, len(new_path))) | ||
| 205 | sys.exit(-1) | ||
| 206 | # pad with zeros | ||
| 207 | new_path += b("\0") * (4096 - len(new_path)) | ||
| 208 | #print "Changing %s to %s at %s" % (str(path), str(new_path), str(offset)) | ||
| 209 | # write it back | ||
| 210 | f.seek(sh_offset + offset) | ||
| 211 | f.write(new_path) | ||
| 212 | offset = offset + 4096 | ||
| 213 | if sysdirs != "" and sysdirslen != "": | ||
| 214 | paths = sysdirs.split(b("\0")) | ||
| 215 | sysdirs = b("") | ||
| 216 | sysdirslen = b("") | ||
| 217 | for path in paths: | ||
| 218 | """ exit the loop when we encounter first empty string """ | ||
| 219 | if path == b(""): | ||
| 220 | break | ||
| 221 | |||
| 222 | new_path = old_prefix.sub(new_prefix, path) | ||
| 223 | sysdirs += new_path + b("\0") | ||
| 224 | |||
| 225 | if arch == 32: | ||
| 226 | sysdirslen += struct.pack("<L", len(new_path)) | ||
| 227 | else: | ||
| 228 | sysdirslen += struct.pack("<Q", len(new_path)) | ||
| 229 | |||
| 230 | """ pad with zeros """ | ||
| 231 | sysdirs += b("\0") * (sysdirs_sect_size - len(sysdirs)) | ||
| 232 | |||
| 233 | """ write the sections back """ | ||
| 234 | f.seek(sysdirs_off) | ||
| 235 | f.write(sysdirs) | ||
| 236 | f.seek(sysdirslen_off) | ||
| 237 | f.write(sysdirslen) | ||
| 238 | |||
| 239 | # MAIN | ||
| 240 | if len(sys.argv) < 4: | ||
| 241 | sys.exit(-1) | ||
| 242 | |||
| 243 | # In python > 3, strings may also contain Unicode characters. So, convert | ||
| 244 | # them to bytes | ||
| 245 | if sys.version_info < (3,): | ||
| 246 | new_prefix = sys.argv[1] | ||
| 247 | new_dl_path = sys.argv[2] | ||
| 248 | else: | ||
| 249 | new_prefix = sys.argv[1].encode() | ||
| 250 | new_dl_path = sys.argv[2].encode() | ||
| 251 | |||
| 252 | executables_list = sys.argv[3:] | ||
| 253 | |||
| 254 | dl_arch = get_dl_arch(new_dl_path) | ||
| 255 | |||
| 256 | errors = False | ||
| 257 | for e in executables_list: | ||
| 258 | perms = os.stat(e)[stat.ST_MODE] | ||
| 259 | if os.access(e, os.W_OK|os.R_OK): | ||
| 260 | perms = None | ||
| 261 | else: | ||
| 262 | os.chmod(e, perms|stat.S_IRWXU) | ||
| 263 | |||
| 264 | try: | ||
| 265 | f = open(e, "r+b") | ||
| 266 | except IOError: | ||
| 267 | exctype, ioex = sys.exc_info()[:2] | ||
| 268 | if ioex.errno == errno.ETXTBSY: | ||
| 269 | print("Could not open %s. File used by another process.\nPlease "\ | ||
| 270 | "make sure you exit all processes that might use any SDK "\ | ||
| 271 | "binaries." % e) | ||
| 272 | else: | ||
| 273 | print("Could not open %s: %s(%d)" % (e, ioex.strerror, ioex.errno)) | ||
| 274 | sys.exit(-1) | ||
| 275 | |||
| 276 | # Save old size and do a size check at the end. Just a safety measure. | ||
| 277 | old_size = os.path.getsize(e) | ||
| 278 | if old_size >= 64: | ||
| 279 | arch = get_arch() | ||
| 280 | if arch and arch == dl_arch: | ||
| 281 | parse_elf_header() | ||
| 282 | if not change_interpreter(e): | ||
| 283 | errors = True | ||
| 284 | change_dl_sysdirs(e) | ||
| 285 | |||
| 286 | """ change permissions back """ | ||
| 287 | if perms: | ||
| 288 | os.chmod(e, perms) | ||
| 289 | |||
| 290 | f.close() | ||
| 291 | |||
| 292 | if old_size != os.path.getsize(e): | ||
| 293 | print("New file size for %s is different. Looks like a relocation error!", e) | ||
| 294 | sys.exit(-1) | ||
| 295 | |||
| 296 | if errors: | ||
| 297 | print("Relocation of one or more executables failed.") | ||
| 298 | sys.exit(-1) | ||
