blob: 4aa40d70eec6a2fb72b3d4ca0f6e6e1e0ba0eb4c [file] [log] [blame]
Brad Bishopc342db32019-05-15 21:57:59 -04001#
Patrick Williams92b42cb2022-09-03 06:53:57 -05002# Copyright OpenEmbedded Contributors
3#
Brad Bishopc342db32019-05-15 21:57:59 -04004# SPDX-License-Identifier: GPL-2.0-only
5#
6
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08007import stat
8import mmap
9import subprocess
10
Patrick Williamsc124f4f2015-09-15 14:41:29 -050011def runstrip(arg):
12 # Function to strip a single file, called from split_and_strip_files below
13 # A working 'file' (one which works on the target architecture)
14 #
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080015 # The elftype is a bit pattern (explained in is_elf below) to tell
Patrick Williamsc124f4f2015-09-15 14:41:29 -050016 # us what type of file we're processing...
17 # 4 - executable
18 # 8 - shared library
19 # 16 - kernel module
20
Andrew Geissler595f6302022-01-24 19:11:47 +000021 if len(arg) == 3:
22 (file, elftype, strip) = arg
23 extra_strip_sections = ''
24 else:
25 (file, elftype, strip, extra_strip_sections) = arg
Patrick Williamsc124f4f2015-09-15 14:41:29 -050026
27 newmode = None
28 if not os.access(file, os.W_OK) or os.access(file, os.R_OK):
29 origmode = os.stat(file)[stat.ST_MODE]
30 newmode = origmode | stat.S_IWRITE | stat.S_IREAD
31 os.chmod(file, newmode)
32
Brad Bishop6e60e8b2018-02-01 10:27:11 -050033 stripcmd = [strip]
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080034 skip_strip = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -050035 # kernel module
36 if elftype & 16:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080037 if is_kernel_module_signed(file):
38 bb.debug(1, "Skip strip on signed module %s" % file)
39 skip_strip = True
40 else:
41 stripcmd.extend(["--strip-debug", "--remove-section=.comment",
42 "--remove-section=.note", "--preserve-dates"])
Patrick Williamsc124f4f2015-09-15 14:41:29 -050043 # .so and shared library
44 elif ".so" in file and elftype & 8:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050045 stripcmd.extend(["--remove-section=.comment", "--remove-section=.note", "--strip-unneeded"])
Patrick Williamsc124f4f2015-09-15 14:41:29 -050046 # shared or executable:
47 elif elftype & 8 or elftype & 4:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050048 stripcmd.extend(["--remove-section=.comment", "--remove-section=.note"])
Andrew Geissler595f6302022-01-24 19:11:47 +000049 if extra_strip_sections != '':
50 for section in extra_strip_sections.split():
51 stripcmd.extend(["--remove-section=" + section])
Patrick Williamsc124f4f2015-09-15 14:41:29 -050052
Brad Bishop6e60e8b2018-02-01 10:27:11 -050053 stripcmd.append(file)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050054 bb.debug(1, "runstrip: %s" % stripcmd)
55
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080056 if not skip_strip:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050057 output = subprocess.check_output(stripcmd, stderr=subprocess.STDOUT)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050058
59 if newmode:
60 os.chmod(file, origmode)
61
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080062# Detect .ko module by searching for "vermagic=" string
63def is_kernel_module(path):
64 with open(path) as f:
65 return mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ).find(b"vermagic=") >= 0
Patrick Williamsc124f4f2015-09-15 14:41:29 -050066
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080067# Detect if .ko module is signed
68def is_kernel_module_signed(path):
69 with open(path, "rb") as f:
70 f.seek(-28, 2)
71 module_tail = f.read()
72 return "Module signature appended" in "".join(chr(c) for c in bytearray(module_tail))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050073
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080074# Return type (bits):
75# 0 - not elf
76# 1 - ELF
77# 2 - stripped
78# 4 - executable
79# 8 - shared library
80# 16 - kernel module
81def is_elf(path):
82 exec_type = 0
83 result = subprocess.check_output(["file", "-b", path], stderr=subprocess.STDOUT).decode("utf-8")
84
85 if "ELF" in result:
86 exec_type |= 1
87 if "not stripped" not in result:
88 exec_type |= 2
89 if "executable" in result:
90 exec_type |= 4
91 if "shared" in result:
92 exec_type |= 8
93 if "relocatable" in result:
94 if path.endswith(".ko") and path.find("/lib/modules/") != -1 and is_kernel_module(path):
95 exec_type |= 16
96 return (path, exec_type)
97
98def is_static_lib(path):
99 if path.endswith('.a') and not os.path.islink(path):
100 with open(path, 'rb') as fh:
101 # The magic must include the first slash to avoid
102 # matching golang static libraries
103 magic = b'!<arch>\x0a/'
104 start = fh.read(len(magic))
105 return start == magic
106 return False
107
108def strip_execs(pn, dstdir, strip_cmd, libdir, base_libdir, d, qa_already_stripped=False):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500109 """
110 Strip executable code (like executables, shared libraries) _in_place_
111 - Based on sysroot_strip in staging.bbclass
112 :param dstdir: directory in which to strip files
113 :param strip_cmd: Strip command (usually ${STRIP})
114 :param libdir: ${libdir} - strip .so files in this directory
115 :param base_libdir: ${base_libdir} - strip .so files in this directory
116 :param qa_already_stripped: Set to True if already-stripped' in ${INSANE_SKIP}
117 This is for proper logging and messages only.
118 """
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800119 import stat, errno, oe.path, oe.utils
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500120
121 elffiles = {}
122 inodes = {}
123 libdir = os.path.abspath(dstdir + os.sep + libdir)
124 base_libdir = os.path.abspath(dstdir + os.sep + base_libdir)
125 exec_mask = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
126 #
127 # First lets figure out all of the files we may have to process
128 #
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800129 checkelf = []
130 inodecache = {}
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500131 for root, dirs, files in os.walk(dstdir):
132 for f in files:
133 file = os.path.join(root, f)
134
135 try:
136 ltarget = oe.path.realpath(file, dstdir, False)
137 s = os.lstat(ltarget)
138 except OSError as e:
139 (err, strerror) = e.args
140 if err != errno.ENOENT:
141 raise
142 # Skip broken symlinks
143 continue
144 if not s:
145 continue
146 # Check its an excutable
147 if s[stat.ST_MODE] & exec_mask \
148 or ((file.startswith(libdir) or file.startswith(base_libdir)) and ".so" in f) \
149 or file.endswith('.ko'):
150 # If it's a symlink, and points to an ELF file, we capture the readlink target
151 if os.path.islink(file):
152 continue
153
154 # It's a file (or hardlink), not a link
155 # ...but is it ELF, and is it already stripped?
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800156 checkelf.append(file)
157 inodecache[file] = s.st_ino
158 results = oe.utils.multiprocess_launch(is_elf, checkelf, d)
159 for (file, elf_file) in results:
160 #elf_file = is_elf(file)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500161 if elf_file & 1:
162 if elf_file & 2:
163 if qa_already_stripped:
164 bb.note("Skipping file %s from %s for already-stripped QA test" % (file[len(dstdir):], pn))
165 else:
166 bb.warn("File '%s' from %s was already stripped, this will prevent future debugging!" % (file[len(dstdir):], pn))
167 continue
168
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800169 if inodecache[file] in inodes:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500170 os.unlink(file)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800171 os.link(inodes[inodecache[file]], file)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500172 else:
173 # break hardlinks so that we do not strip the original.
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800174 inodes[inodecache[file]] = file
175 bb.utils.break_hardlinks(file)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500176 elffiles[file] = elf_file
177
178 #
179 # Now strip them (in parallel)
180 #
181 sfiles = []
182 for file in elffiles:
183 elf_file = int(elffiles[file])
184 sfiles.append((file, elf_file, strip_cmd))
185
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800186 oe.utils.multiprocess_launch(runstrip, sfiles, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500187
188
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500189def file_translate(file):
190 ft = file.replace("@", "@at@")
191 ft = ft.replace(" ", "@space@")
192 ft = ft.replace("\t", "@tab@")
193 ft = ft.replace("[", "@openbrace@")
194 ft = ft.replace("]", "@closebrace@")
195 ft = ft.replace("_", "@underscore@")
196 return ft
197
198def filedeprunner(arg):
199 import re, subprocess, shlex
200
201 (pkg, pkgfiles, rpmdeps, pkgdest) = arg
202 provides = {}
203 requires = {}
204
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500205 file_re = re.compile(r'\s+\d+\s(.*)')
206 dep_re = re.compile(r'\s+(\S)\s+(.*)')
207 r = re.compile(r'[<>=]+\s+\S*')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500208
209 def process_deps(pipe, pkg, pkgdest, provides, requires):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500210 file = None
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500211 for line in pipe.split("\n"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500212
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500213 m = file_re.match(line)
214 if m:
215 file = m.group(1)
216 file = file.replace(pkgdest + "/" + pkg, "")
217 file = file_translate(file)
218 continue
219
220 m = dep_re.match(line)
221 if not m or not file:
222 continue
223
224 type, dep = m.groups()
225
226 if type == 'R':
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500227 i = requires
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500228 elif type == 'P':
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500229 i = provides
230 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500231 continue
232
233 if dep.startswith("python("):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500234 continue
235
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500236 # Ignore all perl(VMS::...) and perl(Mac::...) dependencies. These
237 # are typically used conditionally from the Perl code, but are
238 # generated as unconditional dependencies.
239 if dep.startswith('perl(VMS::') or dep.startswith('perl(Mac::'):
240 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500241
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500242 # Ignore perl dependencies on .pl files.
243 if dep.startswith('perl(') and dep.endswith('.pl)'):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500244 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500245
246 # Remove perl versions and perl module versions since they typically
247 # do not make sense when used as package versions.
248 if dep.startswith('perl') and r.search(dep):
249 dep = dep.split()[0]
250
251 # Put parentheses around any version specifications.
252 dep = r.sub(r'(\g<0>)',dep)
253
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500254 if file not in i:
255 i[file] = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500256 i[file].append(dep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500257
258 return provides, requires
259
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500260 output = subprocess.check_output(shlex.split(rpmdeps) + pkgfiles, stderr=subprocess.STDOUT).decode("utf-8")
261 provides, requires = process_deps(output, pkg, pkgdest, provides, requires)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500262
263 return (pkg, provides, requires)
264
265
266def read_shlib_providers(d):
267 import re
268
269 shlib_provider = {}
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500270 shlibs_dirs = d.getVar('SHLIBSDIRS').split()
Brad Bishop19323692019-04-05 15:28:33 -0400271 list_re = re.compile(r'^(.*)\.list$')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500272 # Go from least to most specific since the last one found wins
273 for dir in reversed(shlibs_dirs):
274 bb.debug(2, "Reading shlib providers in %s" % (dir))
275 if not os.path.exists(dir):
276 continue
Brad Bishop08902b02019-08-20 09:16:51 -0400277 for file in sorted(os.listdir(dir)):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500278 m = list_re.match(file)
279 if m:
280 dep_pkg = m.group(1)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600281 try:
282 fd = open(os.path.join(dir, file))
283 except IOError:
284 # During a build unrelated shlib files may be deleted, so
285 # handle files disappearing between the listdirs and open.
286 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500287 lines = fd.readlines()
288 fd.close()
289 for l in lines:
290 s = l.strip().split(":")
291 if s[0] not in shlib_provider:
292 shlib_provider[s[0]] = {}
293 shlib_provider[s[0]][s[1]] = (dep_pkg, s[2])
294 return shlib_provider