1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
PACKAGEFUNCS =+ "package_generate_dlopen_deps"
python package_generate_dlopen_deps() {
# https://systemd.io/ELF_DLOPEN_METADATA/
import struct, json
def extract_segment(filename, segment):
"""
Return the named segment from the ELF.
"""
import tempfile, subprocess
with tempfile.NamedTemporaryFile() as f:
cmd = [d.getVar("OBJCOPY"), "--dump-section", f"{segment}={f.name}", filename]
subprocess.run(cmd, check=True)
return f.read()
def parse(buffer, is_little):
deps = []
offset = 0
while offset < len(buffer):
format = f"{'<' if is_little else '>'}iii"
name_size, desc_size, note_type = struct.unpack_from(format, buffer, offset)
offset += struct.calcsize(format)
format = f"{name_size}s0i{desc_size}s0i"
if note_type == 0x407c0c0a:
name_b, desc_b = struct.unpack_from(format, buffer, offset)
name = name_b.strip(b"\x00").decode("ascii")
if name == "FDO":
desc = desc_b.strip(b"\x00").decode("utf-8")
deps.append(*json.loads(desc))
offset += struct.calcsize(format)
return deps
dep_map = {
"required": "RDEPENDS",
"recommended": "RRECOMMENDS",
"suggested": "RSUGGESTS"
}
shlibs = oe.package.read_shlib_providers(d)
for pkg, files in pkgfiles.items():
# Skip -dbg packages as we won't need to generate dependencies for those
# but scanning can take time
if pkg.endswith("-dbg"):
continue
for f in files:
# Skip symlinks, just look for real libraries
if cpath.islink(f):
continue
if ".so." in f or f.endswith(".so"):
try:
elf = oe.qa.ELFFile(f)
elf.open()
for dep in parse(extract_segment(f, ".note.dlopen"), elf.isLittleEndian()):
for soname in dep["soname"]:
if soname in shlibs:
# TODO assumes the first match is good
package, version = list(shlibs[soname].values())[0]
dependency = dep_map[dep["priority"]]
bb.note(f"{pkg}: adding {dependency} on {package} via .note.dlopen")
d.appendVar(f"{dependency}:{pkg}", f" {package} (>= {version})")
else:
bb.warn(f"cannot find {soname}")
except oe.qa.NotELFFileError as e:
bb.note(f"Cannot extract ELF notes: {e}")
pass
}
|